Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 3 | PointedEar | 1 | /*------------------------------------------------------------------------------------------*\ |
| 2 | This file contains material supporting chapter 9 of the cookbook: |
||
| 3 | Computer Vision Programming using the OpenCV Library. |
||
| 4 | by Robert Laganiere, Packt Publishing, 2011. |
||
| 5 | |||
| 6 | This program is free software; permission is hereby granted to use, copy, modify, |
||
| 7 | and distribute this source code, or portions thereof, for any purpose, without fee, |
||
| 8 | subject to the restriction that the copyright notice may not be removed |
||
| 9 | or altered from any source or altered source distribution. |
||
| 10 | The software is released on an as-is basis and without any warranties of any kind. |
||
| 11 | In particular, the software is not guaranteed to be fault-tolerant or free from failure. |
||
| 12 | The author disclaims all warranties with regard to this software, any use, |
||
| 13 | and any consequent failure, is purely the responsibility of the user. |
||
| 14 | |||
| 15 | Copyright (C) 2010-2011 Robert Laganiere, www.laganiere.name |
||
| 16 | \*------------------------------------------------------------------------------------------*/ |
||
| 17 | |||
| 18 | #include <iostream> |
||
| 19 | #include <vector> |
||
| 20 | #include <opencv2/core/core.hpp> |
||
| 21 | #include <opencv2/imgproc/imgproc.hpp> |
||
| 22 | #include <opencv2/highgui/highgui.hpp> |
||
| 23 | #include <opencv2/features2d/features2d.hpp> |
||
| 24 | #include <opencv2/calib3d/calib3d.hpp> |
||
| 25 | |||
| 26 | int main() |
||
| 27 | { |
||
| 28 | // Read input images |
||
| 29 | cv::Mat image1= cv::imread("../church01.jpg",0); |
||
| 30 | cv::Mat image2= cv::imread("../church03.jpg",0); |
||
| 31 | if (!image1.data || !image2.data) |
||
| 32 | return 0; |
||
| 33 | |||
| 34 | // Display the images |
||
| 35 | cv::namedWindow("Right Image"); |
||
| 36 | cv::imshow("Right Image",image1); |
||
| 37 | cv::namedWindow("Left Image"); |
||
| 38 | cv::imshow("Left Image",image2); |
||
| 39 | |||
| 40 | // vector of keypoints |
||
| 41 | std::vector<cv::KeyPoint> keypoints1; |
||
| 42 | std::vector<cv::KeyPoint> keypoints2; |
||
| 43 | |||
| 44 | // Construction of the SURF feature detector |
||
| 45 | cv::SurfFeatureDetector surf(3000); |
||
| 46 | |||
| 47 | // Detection of the SURF features |
||
| 48 | surf.detect(image1,keypoints1); |
||
| 49 | surf.detect(image2,keypoints2); |
||
| 50 | |||
| 51 | std::cout << "Number of SURF points (1): " << keypoints1.size() << std::endl; |
||
| 52 | std::cout << "Number of SURF points (2): " << keypoints2.size() << std::endl; |
||
| 53 | |||
| 54 | // Draw the kepoints |
||
| 55 | cv::Mat imageKP; |
||
| 56 | cv::drawKeypoints(image1,keypoints1,imageKP,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); |
||
| 57 | cv::namedWindow("Right SURF Features"); |
||
| 58 | cv::imshow("Right SURF Features",imageKP); |
||
| 59 | cv::drawKeypoints(image2,keypoints2,imageKP,cv::Scalar(255,255,255),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS); |
||
| 60 | cv::namedWindow("Left SURF Features"); |
||
| 61 | cv::imshow("Left SURF Features",imageKP); |
||
| 62 | |||
| 63 | // Construction of the SURF descriptor extractor |
||
| 64 | cv::SurfDescriptorExtractor surfDesc; |
||
| 65 | |||
| 66 | // Extraction of the SURF descriptors |
||
| 67 | cv::Mat descriptors1, descriptors2; |
||
| 68 | surfDesc.compute(image1,keypoints1,descriptors1); |
||
| 69 | surfDesc.compute(image2,keypoints2,descriptors2); |
||
| 70 | |||
| 71 | std::cout << "descriptor matrix size: " << descriptors1.rows << " by " << descriptors1.cols << std::endl; |
||
| 72 | |||
| 73 | // Construction of the matcher |
||
| 74 | cv::BruteForceMatcher<cv::L2<float>> matcher; |
||
| 75 | |||
| 76 | // Match the two image descriptors |
||
| 77 | std::vector<cv::DMatch> matches; |
||
| 78 | matcher.match(descriptors1,descriptors2, matches); |
||
| 79 | |||
| 80 | std::cout << "Number of matched points: " << matches.size() << std::endl; |
||
| 81 | |||
| 82 | // Select few Matches |
||
| 83 | std::vector<cv::DMatch> selMatches; |
||
| 84 | /* |
||
| 85 | keypoints1.push_back(cv::KeyPoint(342.,615.,2)); |
||
| 86 | keypoints2.push_back(cv::KeyPoint(410.,600.,2)); |
||
| 87 | selMatches.push_back(cv::DMatch(keypoints1.size()-1,keypoints2.size()-1,0)); // street light bulb |
||
| 88 | selMatches.push_back(matches[6]); // right tower |
||
| 89 | selMatches.push_back(matches[60]); // left bottom window |
||
| 90 | selMatches.push_back(matches[139]); |
||
| 91 | selMatches.push_back(matches[141]); // middle window |
||
| 92 | selMatches.push_back(matches[213]); |
||
| 93 | selMatches.push_back(matches[273]); |
||
| 94 | |||
| 95 | int kk=0; |
||
| 96 | while (kk<matches.size()) { |
||
| 97 | std::cout<<kk<<std::endl; |
||
| 98 | selMatches.push_back(matches[kk++]); |
||
| 99 | selMatches.pop_back(); |
||
| 100 | cv::waitKey(); |
||
| 101 | } |
||
| 102 | */ |
||
| 103 | |||
| 104 | /* between church01 and church03 */ |
||
| 105 | selMatches.push_back(matches[14]); |
||
| 106 | selMatches.push_back(matches[16]); |
||
| 107 | selMatches.push_back(matches[141]); |
||
| 108 | selMatches.push_back(matches[146]); |
||
| 109 | selMatches.push_back(matches[235]); |
||
| 110 | selMatches.push_back(matches[238]); |
||
| 111 | selMatches.push_back(matches[274]); |
||
| 112 | |||
| 113 | // Draw the selected matches |
||
| 114 | cv::Mat imageMatches; |
||
| 115 | cv::drawMatches(image1,keypoints1, // 1st image and its keypoints |
||
| 116 | image2,keypoints2, // 2nd image and its keypoints |
||
| 117 | // selMatches, // the matches |
||
| 118 | matches, // the matches |
||
| 119 | imageMatches, // the image produced |
||
| 120 | cv::Scalar(255,255,255)); // color of the lines |
||
| 121 | cv::namedWindow("Matches"); |
||
| 122 | cv::imshow("Matches",imageMatches); |
||
| 123 | |||
| 124 | // Convert 1 vector of keypoints into |
||
| 125 | // 2 vectors of Point2f |
||
| 126 | std::vector<int> pointIndexes1; |
||
| 127 | std::vector<int> pointIndexes2; |
||
| 128 | for (std::vector<cv::DMatch>::const_iterator it= selMatches.begin(); |
||
| 129 | it!= selMatches.end(); ++it) { |
||
| 130 | |||
| 131 | // Get the indexes of the selected matched keypoints |
||
| 132 | pointIndexes1.push_back(it->queryIdx); |
||
| 133 | pointIndexes2.push_back(it->trainIdx); |
||
| 134 | } |
||
| 135 | |||
| 136 | // Convert keypoints into Point2f |
||
| 137 | std::vector<cv::Point2f> selPoints1, selPoints2; |
||
| 138 | cv::KeyPoint::convert(keypoints1,selPoints1,pointIndexes1); |
||
| 139 | cv::KeyPoint::convert(keypoints2,selPoints2,pointIndexes2); |
||
| 140 | |||
| 141 | // check by drawing the points |
||
| 142 | std::vector<cv::Point2f>::const_iterator it= selPoints1.begin(); |
||
| 143 | while (it!=selPoints1.end()) { |
||
| 144 | |||
| 145 | // draw a circle at each corner location |
||
| 146 | cv::circle(image1,*it,3,cv::Scalar(255,255,255),2); |
||
| 147 | ++it; |
||
| 148 | } |
||
| 149 | |||
| 150 | it= selPoints2.begin(); |
||
| 151 | while (it!=selPoints2.end()) { |
||
| 152 | |||
| 153 | // draw a circle at each corner location |
||
| 154 | cv::circle(image2,*it,3,cv::Scalar(255,255,255),2); |
||
| 155 | ++it; |
||
| 156 | } |
||
| 157 | |||
| 158 | // Compute F matrix from 7 matches |
||
| 159 | cv::Mat fundemental= cv::findFundamentalMat( |
||
| 160 | cv::Mat(selPoints1), // points in first image |
||
| 161 | cv::Mat(selPoints2), // points in second image |
||
| 162 | CV_FM_7POINT); // 7-point method |
||
| 163 | |||
| 164 | std::cout << "F-Matrix size= " << fundemental.rows << "," << fundemental.cols << std::endl; |
||
| 165 | |||
| 166 | // draw the left points corresponding epipolar lines in right image |
||
| 167 | std::vector<cv::Vec3f> lines1; |
||
| 168 | cv::computeCorrespondEpilines( |
||
| 169 | cv::Mat(selPoints1), // image points |
||
| 170 | 1, // in image 1 (can also be 2) |
||
| 171 | fundemental, // F matrix |
||
| 172 | lines1); // vector of epipolar lines |
||
| 173 | |||
| 174 | // for all epipolar lines |
||
| 175 | for (vector<cv::Vec3f>::const_iterator it= lines1.begin(); |
||
| 176 | it!=lines1.end(); ++it) { |
||
| 177 | |||
| 178 | // draw the epipolar line between first and last column |
||
| 179 | cv::line(image2,cv::Point(0,-(*it)[2]/(*it)[1]), |
||
| 180 | cv::Point(image2.cols,-((*it)[2]+(*it)[0]*image2.cols)/(*it)[1]), |
||
| 181 | cv::Scalar(255,255,255)); |
||
| 182 | } |
||
| 183 | |||
| 184 | // draw the left points corresponding epipolar lines in left image |
||
| 185 | std::vector<cv::Vec3f> lines2; |
||
| 186 | cv::computeCorrespondEpilines(cv::Mat(selPoints2),2,fundemental,lines2); |
||
| 187 | for (vector<cv::Vec3f>::const_iterator it= lines2.begin(); |
||
| 188 | it!=lines2.end(); ++it) { |
||
| 189 | |||
| 190 | // draw the epipolar line between first and last column |
||
| 191 | cv::line(image1,cv::Point(0,-(*it)[2]/(*it)[1]), |
||
| 192 | cv::Point(image1.cols,-((*it)[2]+(*it)[0]*image1.cols)/(*it)[1]), |
||
| 193 | cv::Scalar(255,255,255)); |
||
| 194 | } |
||
| 195 | |||
| 196 | // Display the images with points and epipolar lines |
||
| 197 | cv::namedWindow("Right Image Epilines"); |
||
| 198 | cv::imshow("Right Image Epilines",image1); |
||
| 199 | cv::namedWindow("Left Image Epilines"); |
||
| 200 | cv::imshow("Left Image Epilines",image2); |
||
| 201 | |||
| 202 | /* |
||
| 203 | std::nth_element(matches.begin(), // initial position |
||
| 204 | matches.begin()+matches.size()/2, // 50% |
||
| 205 | matches.end()); // end position |
||
| 206 | // remove all elements after the |
||
| 207 | matches.erase(matches.begin()+matches.size()/2, matches.end()); |
||
| 208 | */ |
||
| 209 | // Convert keypoints into Point2f |
||
| 210 | std::vector<cv::Point2f> points1, points2; |
||
| 211 | for (std::vector<cv::DMatch>::const_iterator it= matches.begin(); |
||
| 212 | it!= matches.end(); ++it) { |
||
| 213 | |||
| 214 | // Get the position of left keypoints |
||
| 215 | float x= keypoints1[it->queryIdx].pt.x; |
||
| 216 | float y= keypoints1[it->queryIdx].pt.y; |
||
| 217 | points1.push_back(cv::Point2f(x,y)); |
||
| 218 | // Get the position of right keypoints |
||
| 219 | x= keypoints2[it->trainIdx].pt.x; |
||
| 220 | y= keypoints2[it->trainIdx].pt.y; |
||
| 221 | points2.push_back(cv::Point2f(x,y)); |
||
| 222 | } |
||
| 223 | |||
| 224 | std::cout << points1.size() << " " << points2.size() << std::endl; |
||
| 225 | |||
| 226 | // Compute F matrix using RANSAC |
||
| 227 | std::vector<uchar> inliers(points1.size(),0); |
||
| 228 | fundemental= cv::findFundamentalMat( |
||
| 229 | cv::Mat(points1),cv::Mat(points2), // matching points |
||
| 230 | inliers, // match status (inlier ou outlier) |
||
| 231 | CV_FM_RANSAC, // RANSAC method |
||
| 232 | 1, // distance to epipolar line |
||
| 233 | 0.98); // confidence probability |
||
| 234 | |||
| 235 | // Read input images |
||
| 236 | image1= cv::imread("../church01.jpg",0); |
||
| 237 | image2= cv::imread("../church03.jpg",0); |
||
| 238 | |||
| 239 | // Draw the epipolar line of few points |
||
| 240 | cv::computeCorrespondEpilines(cv::Mat(selPoints1),1,fundemental,lines1); |
||
| 241 | for (vector<cv::Vec3f>::const_iterator it= lines1.begin(); |
||
| 242 | it!=lines1.end(); ++it) { |
||
| 243 | |||
| 244 | cv::line(image2,cv::Point(0,-(*it)[2]/(*it)[1]), |
||
| 245 | cv::Point(image2.cols,-((*it)[2]+(*it)[0]*image2.cols)/(*it)[1]), |
||
| 246 | cv::Scalar(255,255,255)); |
||
| 247 | } |
||
| 248 | |||
| 249 | cv::computeCorrespondEpilines(cv::Mat(selPoints2),2,fundemental,lines2); |
||
| 250 | for (vector<cv::Vec3f>::const_iterator it= lines2.begin(); |
||
| 251 | it!=lines2.end(); ++it) { |
||
| 252 | |||
| 253 | cv::line(image1,cv::Point(0,-(*it)[2]/(*it)[1]), |
||
| 254 | cv::Point(image1.cols,-((*it)[2]+(*it)[0]*image1.cols)/(*it)[1]), |
||
| 255 | cv::Scalar(255,255,255)); |
||
| 256 | } |
||
| 257 | |||
| 258 | // Draw the inlier points |
||
| 259 | std::vector<cv::Point2f> points1In, points2In; |
||
| 260 | std::vector<cv::Point2f>::const_iterator itPts= points1.begin(); |
||
| 261 | std::vector<uchar>::const_iterator itIn= inliers.begin(); |
||
| 262 | while (itPts!=points1.end()) { |
||
| 263 | |||
| 264 | // draw a circle at each inlier location |
||
| 265 | if (*itIn) { |
||
| 266 | cv::circle(image1,*itPts,3,cv::Scalar(255,255,255),2); |
||
| 267 | points1In.push_back(*itPts); |
||
| 268 | } |
||
| 269 | ++itPts; |
||
| 270 | ++itIn; |
||
| 271 | } |
||
| 272 | |||
| 273 | itPts= points2.begin(); |
||
| 274 | itIn= inliers.begin(); |
||
| 275 | while (itPts!=points2.end()) { |
||
| 276 | |||
| 277 | // draw a circle at each inlier location |
||
| 278 | if (*itIn) { |
||
| 279 | cv::circle(image2,*itPts,3,cv::Scalar(255,255,255),2); |
||
| 280 | points2In.push_back(*itPts); |
||
| 281 | } |
||
| 282 | ++itPts; |
||
| 283 | ++itIn; |
||
| 284 | } |
||
| 285 | |||
| 286 | // Display the images with points |
||
| 287 | cv::namedWindow("Right Image Epilines (RANSAC)"); |
||
| 288 | cv::imshow("Right Image Epilines (RANSAC)",image1); |
||
| 289 | cv::namedWindow("Left Image Epilines (RANSAC)"); |
||
| 290 | cv::imshow("Left Image Epilines (RANSAC)",image2); |
||
| 291 | |||
| 292 | cv::findHomography(cv::Mat(points1In),cv::Mat(points2In),inliers,CV_RANSAC,1.); |
||
| 293 | |||
| 294 | // Read input images |
||
| 295 | image1= cv::imread("../church01.jpg",0); |
||
| 296 | image2= cv::imread("../church03.jpg",0); |
||
| 297 | |||
| 298 | // Draw the inlier points |
||
| 299 | itPts= points1In.begin(); |
||
| 300 | itIn= inliers.begin(); |
||
| 301 | while (itPts!=points1In.end()) { |
||
| 302 | |||
| 303 | // draw a circle at each inlier location |
||
| 304 | if (*itIn) |
||
| 305 | cv::circle(image1,*itPts,3,cv::Scalar(255,255,255),2); |
||
| 306 | |||
| 307 | ++itPts; |
||
| 308 | ++itIn; |
||
| 309 | } |
||
| 310 | |||
| 311 | itPts= points2In.begin(); |
||
| 312 | itIn= inliers.begin(); |
||
| 313 | while (itPts!=points2In.end()) { |
||
| 314 | |||
| 315 | // draw a circle at each inlier location |
||
| 316 | if (*itIn) |
||
| 317 | cv::circle(image2,*itPts,3,cv::Scalar(255,255,255),2); |
||
| 318 | |||
| 319 | ++itPts; |
||
| 320 | ++itIn; |
||
| 321 | } |
||
| 322 | |||
| 323 | // Display the images with points |
||
| 324 | cv::namedWindow("Right Image Homography (RANSAC)"); |
||
| 325 | cv::imshow("Right Image Homography (RANSAC)",image1); |
||
| 326 | cv::namedWindow("Left Image Homography (RANSAC)"); |
||
| 327 | cv::imshow("Left Image Homography (RANSAC)",image2); |
||
| 328 | |||
| 329 | cv::waitKey(); |
||
| 330 | return 0; |
||
| 331 | } |