map_test.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  1. /*M///////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
  4. //
  5. // By downloading, copying, installing or using the software you agree to this license.
  6. // If you do not agree to this license, do not download, install,
  7. // copy or use the software.
  8. //
  9. // Copyright (C) 2013, Alfonso Sanchez-Beato, all rights reserved.
  10. // Third party copyrights are property of their respective owners.
  11. //
  12. // Redistribution and use in source and binary forms, with or without modification,
  13. // are permitted provided that the following conditions are met:
  14. //
  15. // * Redistribution's of source code must retain the above copyright notice,
  16. // this list of conditions and the following disclaimer.
  17. //
  18. // * Redistribution's in binary form must reproduce the above copyright notice,
  19. // this list of conditions and the following disclaimer in the documentation
  20. // and/or other materials provided with the distribution.
  21. //
  22. // * The name of the copyright holders may not be used to endorse or promote products
  23. // derived from this software without specific prior written permission.
  24. //
  25. // This software is provided by the copyright holders and contributors "as is" and
  26. // any express or implied warranties, including, but not limited to, the implied
  27. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  28. // In no event shall the contributors be liable for any direct,
  29. // indirect, incidental, special, exemplary, or consequential damages
  30. // (including, but not limited to, procurement of substitute goods or services;
  31. // loss of use, data, or profits; or business interruption) however caused
  32. // and on any theory of liability, whether in contract, strict liability,
  33. // or tort (including negligence or otherwise) arising in any way out of
  34. // the use of this software, even if advised of the possibility of such damage.
  35. //
  36. //M*/
  37. #include <iostream>
  38. #include <opencv2/imgcodecs.hpp>
  39. #include <opencv2/highgui.hpp> // OpenCV window I/O
  40. #include <opencv2/imgproc.hpp> // OpenCV image transformations
  41. #ifdef COMPARE_FEATURES
  42. #include <opencv2/xfeatures2d.hpp>
  43. #include <opencv2/calib3d.hpp>
  44. #include <opencv2/calib3d/calib3d_c.h>
  45. using namespace cv::xfeatures2d;
  46. #endif
  47. #include "opencv2/reg/mapaffine.hpp"
  48. #include "opencv2/reg/mapshift.hpp"
  49. #include "opencv2/reg/mapprojec.hpp"
  50. #include "opencv2/reg/mappergradshift.hpp"
  51. #include "opencv2/reg/mappergradeuclid.hpp"
  52. #include "opencv2/reg/mappergradsimilar.hpp"
  53. #include "opencv2/reg/mappergradaffine.hpp"
  54. #include "opencv2/reg/mappergradproj.hpp"
  55. #include "opencv2/reg/mapperpyramid.hpp"
  56. static const char* DIFF_IM = "Image difference";
  57. static const char* DIFF_REGPIX_IM = "Image difference: pixel registered";
  58. using namespace cv;
  59. using namespace cv::reg;
  60. using namespace std;
  61. static void showDifference(const Mat& image1, const Mat& image2, const char* title)
  62. {
  63. Mat img1, img2;
  64. image1.convertTo(img1, CV_32FC3);
  65. image2.convertTo(img2, CV_32FC3);
  66. if(img1.channels() != 1)
  67. cvtColor(img1, img1, COLOR_BGR2GRAY);
  68. if(img2.channels() != 1)
  69. cvtColor(img2, img2, COLOR_BGR2GRAY);
  70. Mat imgDiff;
  71. img1.copyTo(imgDiff);
  72. imgDiff -= img2;
  73. imgDiff /= 2.f;
  74. imgDiff += 128.f;
  75. Mat imgSh;
  76. imgDiff.convertTo(imgSh, CV_8UC3);
  77. imshow(title, imgSh);
  78. }
  79. static void testShift(const Mat& img1)
  80. {
  81. Mat img2;
  82. // Warp original image
  83. Vec<double, 2> shift(5., 5.);
  84. MapShift mapTest(shift);
  85. mapTest.warp(img1, img2);
  86. showDifference(img1, img2, DIFF_IM);
  87. // Register
  88. Ptr<MapperGradShift> mapper = makePtr<MapperGradShift>();
  89. MapperPyramid mappPyr(mapper);
  90. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  91. // Print result
  92. MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get());
  93. cout << endl << "--- Testing shift mapper ---" << endl;
  94. cout << Mat(shift) << endl;
  95. cout << Mat(mapShift->getShift()) << endl;
  96. // Display registration accuracy
  97. Mat dest;
  98. mapShift->inverseWarp(img2, dest);
  99. showDifference(img1, dest, DIFF_REGPIX_IM);
  100. waitKey(0);
  101. destroyWindow(DIFF_IM);
  102. destroyWindow(DIFF_REGPIX_IM);
  103. }
  104. static void testEuclidean(const Mat& img1)
  105. {
  106. Mat img2;
  107. // Warp original image
  108. double theta = 3*CV_PI/180;
  109. double cosT = cos(theta);
  110. double sinT = sin(theta);
  111. Matx<double, 2, 2> linTr(cosT, -sinT, sinT, cosT);
  112. Vec<double, 2> shift(5., 5.);
  113. MapAffine mapTest(linTr, shift);
  114. mapTest.warp(img1, img2);
  115. showDifference(img1, img2, DIFF_IM);
  116. // Register
  117. Ptr<MapperGradEuclid> mapper = makePtr<MapperGradEuclid>();
  118. MapperPyramid mappPyr(mapper);
  119. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  120. // Print result
  121. MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
  122. cout << endl << "--- Testing Euclidean mapper ---" << endl;
  123. cout << Mat(linTr) << endl;
  124. cout << Mat(shift) << endl;
  125. cout << Mat(mapAff->getLinTr()) << endl;
  126. cout << Mat(mapAff->getShift()) << endl;
  127. // Display registration accuracy
  128. Mat dest;
  129. mapAff->inverseWarp(img2, dest);
  130. showDifference(img1, dest, DIFF_REGPIX_IM);
  131. waitKey(0);
  132. destroyWindow(DIFF_IM);
  133. destroyWindow(DIFF_REGPIX_IM);
  134. }
  135. static void testSimilarity(const Mat& img1)
  136. {
  137. Mat img2;
  138. // Warp original image
  139. double theta = 3*CV_PI/180;
  140. double scale = 0.95;
  141. double a = scale*cos(theta);
  142. double b = scale*sin(theta);
  143. Matx<double, 2, 2> linTr(a, -b, b, a);
  144. Vec<double, 2> shift(5., 5.);
  145. MapAffine mapTest(linTr, shift);
  146. mapTest.warp(img1, img2);
  147. showDifference(img1, img2, DIFF_IM);
  148. // Register
  149. Ptr<MapperGradSimilar> mapper = makePtr<MapperGradSimilar>();
  150. MapperPyramid mappPyr(mapper);
  151. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  152. // Print result
  153. MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
  154. cout << endl << "--- Testing similarity mapper ---" << endl;
  155. cout << Mat(linTr) << endl;
  156. cout << Mat(shift) << endl;
  157. cout << Mat(mapAff->getLinTr()) << endl;
  158. cout << Mat(mapAff->getShift()) << endl;
  159. // Display registration accuracy
  160. Mat dest;
  161. mapAff->inverseWarp(img2, dest);
  162. showDifference(img1, dest, DIFF_REGPIX_IM);
  163. waitKey(0);
  164. destroyWindow(DIFF_IM);
  165. destroyWindow(DIFF_REGPIX_IM);
  166. }
  167. static void testAffine(const Mat& img1)
  168. {
  169. Mat img2;
  170. // Warp original image
  171. Matx<double, 2, 2> linTr(1., 0.1, -0.01, 1.);
  172. Vec<double, 2> shift(1., 1.);
  173. MapAffine mapTest(linTr, shift);
  174. mapTest.warp(img1, img2);
  175. showDifference(img1, img2, DIFF_IM);
  176. // Register
  177. Ptr<MapperGradAffine> mapper = makePtr<MapperGradAffine>();
  178. MapperPyramid mappPyr(mapper);
  179. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  180. // Print result
  181. MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
  182. cout << endl << "--- Testing affine mapper ---" << endl;
  183. cout << Mat(linTr) << endl;
  184. cout << Mat(shift) << endl;
  185. cout << Mat(mapAff->getLinTr()) << endl;
  186. cout << Mat(mapAff->getShift()) << endl;
  187. // Display registration accuracy
  188. Mat dest;
  189. mapAff->inverseWarp(img2, dest);
  190. showDifference(img1, dest, DIFF_REGPIX_IM);
  191. waitKey(0);
  192. destroyWindow(DIFF_IM);
  193. destroyWindow(DIFF_REGPIX_IM);
  194. }
  195. static void testProjective(const Mat& img1)
  196. {
  197. Mat img2;
  198. // Warp original image
  199. Matx<double, 3, 3> projTr(1., 0., 0., 0., 1., 0., 0.0001, 0.0001, 1);
  200. MapProjec mapTest(projTr);
  201. mapTest.warp(img1, img2);
  202. showDifference(img1, img2, DIFF_IM);
  203. // Register
  204. Ptr<MapperGradProj> mapper = makePtr<MapperGradProj>();
  205. MapperPyramid mappPyr(mapper);
  206. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  207. // Print result
  208. MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get());
  209. mapProj->normalize();
  210. cout << endl << "--- Testing projective transformation mapper ---" << endl;
  211. cout << Mat(projTr) << endl;
  212. cout << Mat(mapProj->getProjTr()) << endl;
  213. // Display registration accuracy
  214. Mat dest;
  215. mapProj->inverseWarp(img2, dest);
  216. showDifference(img1, dest, DIFF_REGPIX_IM);
  217. waitKey(0);
  218. destroyWindow(DIFF_IM);
  219. destroyWindow(DIFF_REGPIX_IM);
  220. }
  221. #ifdef COMPARE_FEATURES
  222. //
  223. // Following an example from
  224. // http:// ramsrigoutham.com/2012/11/22/panorama-image-stitching-in-opencv/
  225. //
  226. static void calcHomographyFeature(const Mat& image1, const Mat& image2)
  227. {
  228. static const char* difffeat = "Difference feature registered";
  229. Mat gray_image1;
  230. Mat gray_image2;
  231. // Convert to Grayscale
  232. if(image1.channels() != 1)
  233. cvtColor(image1, gray_image1, COLOR_BGR2GRAY);
  234. else
  235. image1.copyTo(gray_image1);
  236. if(image2.channels() != 1)
  237. cvtColor(image2, gray_image2, COLOR_BGR2GRAY);
  238. else
  239. image2.copyTo(gray_image2);
  240. //-- Step 1: Detect the keypoints using SIFT or SURF Detector
  241. #ifdef USE_SIFT
  242. Ptr<Feature2D> features = SIFT::create();
  243. #else
  244. int minHessian = 400;
  245. Ptr<Feature2D> features = SURF::create(minHessian);
  246. #endif
  247. std::vector<KeyPoint> keypoints_object, keypoints_scene;
  248. features->detect(gray_image1, keypoints_object);
  249. features->detect(gray_image2, keypoints_scene);
  250. //-- Step 2: Calculate descriptors (feature vectors)
  251. Mat descriptors_object, descriptors_scene;
  252. features->compute(gray_image1, keypoints_object, descriptors_object);
  253. features->compute(gray_image2, keypoints_scene, descriptors_scene);
  254. //-- Step 3: Matching descriptor vectors using FLANN matcher
  255. FlannBasedMatcher matcher;
  256. std::vector<DMatch> matches;
  257. matcher.match(descriptors_object, descriptors_scene, matches);
  258. double max_dist = 0; double min_dist = 100;
  259. //-- Quick calculation of max and min distances between keypoints
  260. for(int i = 0; i < descriptors_object.rows; i++)
  261. {
  262. double dist = matches[i].distance;
  263. if( dist < min_dist ) min_dist = dist;
  264. if( dist > max_dist ) max_dist = dist;
  265. }
  266. //-- Use only "good" matches (i.e. whose distance is less than 3*min_dist)
  267. std::vector<DMatch> good_matches;
  268. for(int i = 0; i < descriptors_object.rows; i++) {
  269. if(matches[i].distance < 3*min_dist) {
  270. good_matches.push_back( matches[i]);
  271. }
  272. }
  273. std::vector< Point2f > obj;
  274. std::vector< Point2f > scene;
  275. for(size_t i = 0; i < good_matches.size(); i++)
  276. {
  277. //-- Get the keypoints from the good matches
  278. obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
  279. scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
  280. }
  281. // Find the Homography Matrix
  282. Mat H = findHomography( obj, scene, RANSAC );
  283. // Use the Homography Matrix to warp the images
  284. Mat result;
  285. Mat Hinv = H.inv();
  286. warpPerspective(image2, result, Hinv, image1.size());
  287. cout << "--- Feature method\n" << H << endl;
  288. Mat imf1, resf;
  289. image1.convertTo(imf1, CV_64FC3);
  290. result.convertTo(resf, CV_64FC3);
  291. showDifference(imf1, resf, difffeat);
  292. }
  293. static void calcHomographyPixel(const Mat& img1, const Mat& img2)
  294. {
  295. static const char* diffpixel = "Difference pixel registered";
  296. // Register using pixel differences
  297. Ptr<MapperGradProj> mapper = makePtr<MapperGradProj>();
  298. MapperPyramid mappPyr(mapper);
  299. Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
  300. // Print result
  301. MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get());
  302. mapProj->normalize();
  303. cout << "--- Pixel-based method\n" << Mat(mapProj->getProjTr()) << endl;
  304. // Display registration accuracy
  305. Mat dest;
  306. mapProj->inverseWarp(img2, dest);
  307. showDifference(img1, dest, diffpixel);
  308. }
  309. static void comparePixelVsFeature(const Mat& img1_8b, const Mat& img2_8b)
  310. {
  311. static const char* difforig = "Difference non-registered";
  312. // Show difference of images
  313. Mat img1, img2;
  314. img1_8b.convertTo(img1, CV_64FC3);
  315. img2_8b.convertTo(img2, CV_64FC3);
  316. showDifference(img1, img2, difforig);
  317. cout << endl << "--- Comparing feature-based with pixel difference based ---" << endl;
  318. // Register using SURF keypoints
  319. calcHomographyFeature(img1_8b, img2_8b);
  320. // Register using pixel differences
  321. calcHomographyPixel(img1, img2);
  322. waitKey(0);
  323. }
  324. #endif
  325. int main(void)
  326. {
  327. Mat img1;
  328. img1 = imread("home.png", IMREAD_UNCHANGED);
  329. if(!img1.data) {
  330. cout << "Could not open or find file" << endl;
  331. return -1;
  332. }
  333. // Convert to double, 3 channels
  334. img1.convertTo(img1, CV_64FC3);
  335. testShift(img1);
  336. testEuclidean(img1);
  337. testSimilarity(img1);
  338. testAffine(img1);
  339. testProjective(img1);
  340. #ifdef COMPARE_FEATURES
  341. Mat imgcmp1 = imread("LR_05.png", IMREAD_UNCHANGED);
  342. if(!imgcmp1.data) {
  343. cout << "Could not open or find file" << endl;
  344. return -1;
  345. }
  346. Mat imgcmp2 = imread("LR_06.png", IMREAD_UNCHANGED);
  347. if(!imgcmp2.data) {
  348. cout << "Could not open or find file" << endl;
  349. return -1;
  350. }
  351. comparePixelVsFeature(imgcmp1, imgcmp2);
  352. #endif
  353. return 0;
  354. }