source: proiecte/pmake3d/make3d_original/Make3dSingleImageStanford_version0.1/third_party/SURF-V1.0.8/symmatchRConS_thre_ann.cpp @ 37

Last change on this file since 37 was 37, checked in by (none), 14 years ago

Added original make3d

File size: 15.6 KB
Line 
1/*
2 * Speeded-Up Robust Features (SURF)
3 * http://people.ee.ethz.ch/~surf
4 *
5 * Sample application for feature matching using nearest-neighbor
6 * ratio method.
7 *
8 * BUILD USING "make match.ln".
9 *
10 * Author: Andreas Ess
11 *
12 * Copyright (2006): ETH Zurich, Switzerland
13 * Katholieke Universiteit Leuven, Belgium
14 * All rights reserved.
15 *
16 * For details, see the paper:
17 * Herbert Bay,  Tinne Tuytelaars,  Luc Van Gool,
18 *  "SURF: Speeded Up Robust Features"
19 * Proceedings of the ninth European Conference on Computer Vision, May 2006
20 *
21 * Permission to use, copy, modify, and distribute this software and
22 * its documentation for educational, research, and non-commercial
23 * purposes, without fee and without a signed licensing agreement, is
24 * hereby granted, provided that the above copyright notice and this
25 * paragraph appear in all copies modifications, and distributions.
26 *
27 * Any commercial use or any redistribution of this software
28 * requires a license from one of the above mentioned establishments.
29 *
30 * For further details, contact Andreas Ess (aess@vision.ee.ethz.ch).
31 */
32
33/**
34   modified by Jeff Michels to add the requirement that matches
35   are only output if the point in im2 is the best match for the
36   point in im1 AND vice versa.
37**/
38
39#include <vector>
40#include <string>
41#include <cstdlib>
42#include <iostream>
43#include <fstream>
44#include <cmath>
45
46#include "ipoint.h"
47
48
49#include "image.h"
50#include "imload.h"
51
52
53using namespace std;
54using namespace surf;
55
56// Length of descriptor vector, ugly, global variable
57unsigned int vlen;
58
59// Calculate square distance of two vectors
60inline double distSquare(double *v1, double *v2, int n) {
61        double dsq = 0.;
62        while (n--) {
63                dsq += (*v1 - *v2) * (*v1 - *v2);
64                v1++;
65                v2++;
66        }
67        return dsq;
68}
69
70// Calculate square distance of two vectors
71inline double distSquare(double *v1, double *v2, int n, double *limit) {
72        double dsq = 0.;
73        while (n-- && dsq <= *limit) {
74                dsq += (*v1 - *v2) * (*v1 - *v2);
75                v1++;
76                v2++;
77        }
78        return dsq;
79}
80
81
82// Find closest interest point in a list, given one interest point
83int findMatch(const Ipoint& ip1, const vector< Ipoint >& ipts) {
84        double mind = 1e100, second = 1e100; //Magic number Min??
85        int match = -1;
86
87        for (unsigned i = 0; i < ipts.size(); i++) {
88                // Take advantage of Laplacian to speed up matching
89                if (ipts[i].laplace != ip1.laplace)
90                        continue;
91
92                double d = distSquare(ipts[i].ivec, ip1.ivec, vlen);
93
94                if (d < mind) {
95                        second = mind;
96                        mind = d;
97                        match = i;
98                } else if (d < second) {
99                        second = d;
100                }
101        }
102
103        if (mind < 0.7 * second) //0.8 //Magic number Min??
104            //Answer: in SIFT paper 0.8 is used for discarding 90% of false match but discard only 5% of correct matches
105                return match;
106
107        return -1;
108}
109
110void printAllDistances(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2) {
111  for (unsigned int i = 0; i < ipts1.size(); i++) {
112    for (unsigned int j = 0; j < ipts2.size(); j++) {
113      double dist = distSquare(ipts1[i].ivec, ipts2[j].ivec, vlen);
114      cout << i << " " << j << " " << dist << endl;
115    }
116  }
117}
118
119//Min add RoughConstrainCheck to check if the Constrain been meet
120inline bool RoughConstrainCheck(const Ipoint& ipts1, const Ipoint& ipts2, const Ipoint& ConS1, const Ipoint& ConS2){
121
122//      bool Sat = false;
123        // check if ipts2 satisfy constrain1 or ipts1 satisfy constrain2
124
125/*      if (ipts2.x <= ConS1.ivec[1] && ipts2.x >= ConS1.ivec[0] && ipts2.y >= ConS1.ivec[2] && ipts2.y <= ConS1.ivec[3])
126                                        return true;
127
128        if (ipts1.x <= ConS2.ivec[1] && ipts1.x >= ConS2.ivec[0] && ipts1.y >= ConS2.ivec[2] && ipts1.y <= ConS2.ivec[3])
129                        return true;
130*/
131       
132        return  (ipts2.x <= ConS1.ivec[1] && ipts2.x >= ConS1.ivec[0] && ipts2.y >= ConS1.ivec[2] && ipts2.y <= ConS1.ivec[3]) ||
133                (ipts1.x <= ConS2.ivec[1] && ipts1.x >= ConS2.ivec[0] && ipts1.y >= ConS2.ivec[2] && ipts1.y <= ConS2.ivec[3]);
134}
135
136//Min add ConstrainCheck to check if the Constrain been meet
137inline bool ConstrainCheck(const Ipoint& ipts1, const Ipoint& ipts2, const Ipoint& ConS1, const Ipoint& ConS2){
138
139//      bool Sat = false;
140        // check if ipts2 satisfy constrain1 or ipts1 satisfy constrain2
141
142        float y2 = (ipts2.x - ConS1.ivec[4])*ConS1.ivec[2] + (ipts2.y - ConS1.ivec[5])*ConS1.ivec[3];
143        if (y2 <= ConS1.ivec[7] && y2 >= -ConS1.ivec[7] ){
144                float x2 = (ipts2.x - ConS1.ivec[4])*ConS1.ivec[0] + (ipts2.y - ConS1.ivec[5])*ConS1.ivec[1];
145                if (x2 >= 0 && x2 <= ConS1.ivec[6]){
146                                        return true;
147                }
148        }
149
150        float y1 = (ipts1.x - ConS2.ivec[4])*ConS2.ivec[2] + (ipts1.y - ConS2.ivec[5])*ConS2.ivec[3];
151        if (y1 <= ConS2.ivec[7] && y1 >= -ConS2.ivec[7]){
152                float x1 = (ipts1.x - ConS2.ivec[4])*ConS2.ivec[0] + (ipts1.y - ConS2.ivec[5])*ConS2.ivec[1];
153                if (x1 >= 0 && x1 <= ConS2.ivec[6]){
154                        return true;
155                }
156        }
157       
158        return false;       
159}
160
161// essentially the same as findMatches except that it deletes matches that
162// aren't symetric.
163// Really time-consuming function
164vector <int> symMatches(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2, const vector< Ipoint >& ConS1, const vector< Ipoint >& ConS2, const vector< Ipoint >& ConSRough1, const vector< Ipoint >& ConSRough2, const double abs_thre, const double ratio_thre) {
165  vector< int > bestIndex1(ipts1.size());
166  vector< int > bestIndex2(ipts2.size());
167  vector< double > bestScore1(ipts1.size());
168  vector< double > bestScore2(ipts2.size());
169  vector< double > secondScore1(ipts1.size());
170  vector< double > secondScore2(ipts2.size());
171
172  // Initialize all of the vectors
173  for (unsigned int i = 0; i < ipts1.size(); i++) {
174    bestIndex1[i] = -1;
175    bestScore1[i]= 1e100;
176    secondScore1[i] = 1e100;
177  }
178  for (unsigned int j = 0; j < ipts2.size(); j++) {
179    bestIndex2[j] = -1;
180    bestScore2[j]= 1e100;
181    secondScore2[j] = 1e100;
182  }
183
184  // Main loop - per point in im1 do a linear scan of points in im2
185  int total = 0;
186  double limit = 1e100;
187  for (unsigned int i = 0; i < ipts1.size(); i++) {
188    for (unsigned int j = 0; j < ipts2.size(); j++) {
189       if (ipts1[i].laplace != ipts2[j].laplace)
190                        continue;
191        // do a super-fast rough check
192        if ( !RoughConstrainCheck(ipts1[i], ipts2[j], ConSRough1[i], ConSRough2[j]))
193                        continue;
194        //Min add ConstrainCheck();
195        if ( !ConstrainCheck(ipts1[i], ipts2[j], ConS1[i], ConS2[j]))
196                        continue;
197
198        //record best and second best scores and best index for each
199      //point in each image
200//      double dist = distSquare(ipts1[i].ivec, ipts2[j].ivec, vlen);
201      limit = (secondScore1[i] > secondScore2[j]) ? secondScore1[i] : secondScore2[j];
202      double dist = distSquare(ipts1[i].ivec, ipts2[j].ivec, vlen, &limit);
203      if (dist < bestScore1[i]) {
204        bestIndex1[i] = j;
205        secondScore1[i] = bestScore1[i];
206        bestScore1[i] = dist;
207      } else if (dist < secondScore1[i]) {
208        secondScore1[i] = dist;
209      }
210      if (dist < bestScore2[j]) {
211        bestIndex2[j] = i;
212        secondScore2[j] = bestScore2[j];
213        bestScore2[j] = dist;
214      } else if (dist < secondScore2[j]) {
215        secondScore2[j] = dist;
216      }
217    }
218  }
219  //cout << "Matched " << total << " points." << endl;
220  //return bestIndex1; //for threshold
221
222  /*******************************
223     //killed same img matches - should be covered by match symetry anyway
224 
225  //update second scores with best match from same image (for image 1)
226  for (int i = 0; i < ipts1.size(); i++) {
227    for (int j = i+1; j < ipts1.size(); j++) {
228      double dist = distSquare(ipts1[i].ivec, ipts1[j].ivec, vlen);
229      if (dist < secondScore1[i]){// && dist < 0.3) {
230        //cout << "im1 point " << i << " best: " << bestScore1[i] << " second: " << secondScore1[i] <<
231        //  "im1 point " << j << ": " << dist << endl;
232        secondScore1[i] = dist;
233      }
234    }
235  }
236
237  //update second scores with best match from same image (for image 2)
238  for (int i = 0; i < ipts2.size(); i++) {
239    for (int j = i+1; j < ipts2.size(); j++) {
240      double dist = distSquare(ipts2[i].ivec, ipts2[j].ivec, vlen);
241      if (dist < secondScore2[j]){// && dist < 0.3){
242        //cout << "im2 point " << i << " best: " << bestScore2[i] << " second: " << secondScore2[i] <<
243        //  "im2 point " << j << ": " << dist << endl;
244        secondScore2[i] = dist;
245      }
246    }
247  }
248  ******************************/
249
250  //if the best score is no longer the best or isn't good enough relative
251  // to the second, kill the index
252
253  //image 1 //Min change 0.85 to 0.7
254  for (unsigned int i = 0; i < ipts1.size(); i++) {
255    if (secondScore1[i] * ratio_thre < bestScore1[i] || bestScore1[i] > abs_thre) {
256      bestIndex1[i] = -1;
257    }
258  }
259
260  //image 2 //Min change 0.85 to 0.7
261  for (unsigned int i = 0; i < ipts2.size(); i++) {
262    if (secondScore2[i] * ratio_thre < bestScore2[i] || bestScore2[i] > abs_thre) {
263      bestIndex2[i] = -1;
264    }
265  }
266
267  //if the best matches aren't mutual, kill the match
268  for (unsigned int i = 0; i < ipts1.size(); i++) {
269    int index = bestIndex1[i];
270    if (index != -1) {
271      if (bestIndex2[index] != i) {
272        //cout << "Non symetric match.  im1(" << i << ")->" << index << " but im2(" << index <<
273        //  ")->" << bestIndex2[index] << endl;
274        bestIndex1[i] = -1;
275      } else {
276        cout << " Matched feature " << i << " in image 1 with feature "
277             << index << " in image 2." << endl;
278        total++;
279      }
280    }
281  }
282
283  cout << "Matched " << total << " points." << endl;
284  return bestIndex1;
285}
286
287// Find all possible matches between two images
288// need to change to reduce the search space by knowing GPS information Min
289vector< int > findMatches(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2) {
290        vector< int > matches(ipts1.size());
291        int c = 0;
292        for (unsigned i = 0; i < ipts1.size(); i++) {
293                int match = findMatch(ipts1[i], ipts2);
294                matches[i] = match;
295                if (match != -1) {
296                        cout << " Matched feature " << i << " in image 1 with feature "
297                                << match << " in image 2." << endl;
298                        c++;
299                }
300        }
301        cout << " --> Matched " << c << " features of " << ipts1.size() << " in image 1." << endl;
302        return matches;
303}
304
305// Load the interest points from a regular ASCII file
306void loadIpoints(string sFileName, vector< Ipoint >& ipts) {
307        ifstream ipfile(sFileName.c_str());
308        if( !ipfile ) {
309                cerr << "ERROR in loadIpoints(): "
310                        << "Couldn't open file '" << sFileName.c_str() << "'!" << endl;
311                return;
312        }
313
314        // Load the file header
315        unsigned count;
316        ipfile >> vlen >> count;
317
318        // create a new interest point vector
319        ipts.clear();
320        ipts.resize(count);
321        //cout << "The number of features" << count << endl;
322
323        // Load the interest points in Mikolajczyk's format
324        for (unsigned n = 0; n < count; n++) {
325                // circular regions with diameter 5 x scale
326                float x, y, a, b, c;
327
328                // Read in region data, though not needed for actual matching
329                ipfile >> x >> y >> a >> b >> c;
330
331                float det = sqrt((a-c)*(a-c) + 4.0*b*b);
332                float e1 = 0.5*(a+c + det);
333                float e2 = 0.5*(a+c - det);
334                float l1 = (1.0/sqrt(e1));
335                float l2 = (1.0/sqrt(e2));
336                float sc = sqrt( l1*l2 );
337
338                ipts[n].x = x;
339                ipts[n].y = y;
340                ipts[n].scale = sc/2.5;
341
342                // Read in Laplacian
343                ipfile >> ipts[n].laplace;
344
345                // SURF makes Laplacian part of descriptor, so skip it..
346                ipts[n].ivec = new double[vlen - 1];
347                for (unsigned j = 0; j < vlen - 1; j++)
348                        ipfile >> ipts[n].ivec[j];
349        }
350}
351
352void drawLine(Image *im, int x1, int y1, int x2, int y2) {
353        if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0) ||
354            (x1 >= im->getWidth() && x2 >= im->getWidth()) ||
355            (y1 >= im->getHeight() && y2 >= im->getHeight()))
356                return;
357
358        bool steep = std::abs(y2 - y1) > std::abs(x2 - x1);
359        if (steep) {
360                int t;
361                t = x1;
362                x1 = y1;
363                y1 = t;
364                t = y2;
365                y2 = x2;
366                x2 = t;
367        }
368
369        if (x1 > x2) {
370                // Swap points
371                int t;
372                t = x1;
373                x1 = x2;
374                x2 = t;
375                t = y1;
376                y1 = y2;
377                y2 = t;
378        }
379
380        int deltax = x2 - x1;
381        int deltay = std::abs(y2 - y1);
382
383        int error = 0;
384        int y = y1;
385        int ystep = y1 < y2 ? 1 : -1;
386
387        for (int x = x1; x < x2; x++) {
388                if (steep) {
389                        if (x >= 0 && y >= 0 && y < im->getWidth() && x < im->getHeight())
390                                im->setPix(y, x, 1);
391                } else {
392                        if (x >= 0 && y >= 0 && x < im->getWidth() && y < im->getHeight())
393                                im->setPix(x, y, 1);
394
395                }
396                error += deltay;
397
398                if (2 * error > deltax) {
399                        y += ystep;
400                        error -= deltax;
401                }
402        }
403}
404
405void drawCross(Image *im, int x, int y, int s = 5) {
406        for (int x1 = x - s; x1 <= x + s; x1++)
407                im->setPix(x1, y, 1);
408        for (int y1 = y - s; y1 <= y + s; y1++)
409                im->setPix(x, y1, 1);
410}
411
412int main(int argc, char **argv) {
413        Image *im1, *im2;
414
415        ImLoad ImageLoader;
416        vector< Ipoint > ipts1, ipts2, ConS1, ConS2, ConSRough1, ConSRough2; //Min
417        bool drawc = false;
418        bool usesym = false;
419        bool printAllDist = false;
420        double abs_thre = 0.3;
421        double ratio_thre = 0.7;
422       
423        char ofname[100];
424
425        im1 = im2 = NULL;
426        ofname[0] = 0;
427
428        // Read the arguments
429        int arg = 0;
430        while (++arg < argc) { 
431                if (! strcmp(argv[arg], "-k1"))
432                        loadIpoints(argv[++arg], ipts1);
433                if (! strcmp(argv[arg], "-k2"))
434                        loadIpoints(argv[++arg], ipts2);
435                //Min -------------------------------------
436                if (! strcmp(argv[arg], "-S1")) 
437                        loadIpoints(argv[++arg], ConS1);
438                if (! strcmp(argv[arg], "-S2"))
439                        loadIpoints(argv[++arg], ConS2);
440                if (! strcmp(argv[arg], "-RS1")) 
441                        loadIpoints(argv[++arg], ConSRough1);
442                if (! strcmp(argv[arg], "-RS2"))
443                        loadIpoints(argv[++arg], ConSRough2);
444                //Min -------------------------------------
445
446                if (! strcmp(argv[arg], "-im1"))
447                        im1 = ImageLoader.readImage(argv[++arg]); 
448                if (! strcmp(argv[arg], "-im2"))
449                        im2 = ImageLoader.readImage(argv[++arg]); 
450                if (! strcmp(argv[arg], "-o"))
451                        strcpy(ofname, argv[++arg]);
452                if (! strcmp(argv[arg], "-c"))
453                        drawc = true;
454                if (! strcmp(argv[arg], "-s"))
455                        usesym = true;
456                if (! strcmp(argv[arg], "-d"))
457                        printAllDist = true;
458                if (! strcmp(argv[arg], "-abs"))
459                        abs_thre = strtod( argv[++arg], NULL);
460                if (! strcmp(argv[arg], "-ratio"))
461                        ratio_thre = strtod( argv[++arg], NULL);
462
463        }
464       
465
466        if (ipts1.size() == 0 || ipts2.size() == 0) {
467                cout << "Usage:" << endl;
468                cout << " match [-s] -k1 out1.surf -k2 out2.surf -im1 img1.pgm -im2 img2.pgm -o out.pgm" << endl << endl;
469                cout << "For each feature in first descriptor file, find best in second according to "
470                        << "nearest neighbor ratio strategy. Display matches in out.pgm, generated "
471                        << "from img1.pgm and img2.pgm. Use -c to draw crosses at interest points." << endl;
472
473                cout << "use -s to require that the best match be symetric."<<endl;
474                cout << "use -d to print out all of the n*m distances between points instead of matching."<<endl;
475                cout << "use -abs to set absolute threshould and -ratio to set rative threshould."<<endl;
476                return 1;
477        }
478
479        vector< int > matches;
480         
481        if (usesym) {
482          cerr << "Using symmetricConS matches, using descriptor length " << vlen << ConSRough1[0].ivec[3] << abs_thre << ratio_thre<< endl;
483//        cout << "test CONSRough" << ConSRough1[1].ivec[1] << endl;
484                matches = symMatches(ipts1, ipts2, ConS1, ConS2, ConSRough1, ConSRough2, abs_thre, ratio_thre);//Min
485        } else if (printAllDist){
486          printAllDistances(ipts1, ipts2);
487        } else {
488          matches = findMatches(ipts1, ipts2);
489        }
490
491
492        if (im1 != NULL && im2 != NULL && ofname[0] != 0) {
493                Image res(max(im1->getWidth(), im2->getWidth()), im1->getHeight() + im2->getHeight());
494                for (int x = 0; x < im1->getWidth(); x++)
495                        for (int y = 0; y < im1->getHeight(); y++)
496                                res.setPix(x, y, im1->getPix(x, y));
497                for (int x = 0; x < im2->getWidth(); x++)
498                        for (int y = 0; y < im2->getHeight(); y++)
499                                res.setPix(x, y + im1->getHeight(), im2->getPix(x, y));
500
501                // Draw lines for matches
502                for (unsigned i = 0; i < matches.size(); i++) {
503                        if (matches[i] != -1) {
504                                drawLine(&res, (int)ipts1[i].x, (int)ipts1[i].y,
505                                        (int)ipts2[matches[i]].x, (int)(ipts2[matches[i]].y + im1->getHeight()));
506                        }
507                }
508
509                // Draw crosses at interest point locations
510                if (drawc) {
511                        for (unsigned i = 0; i < ipts1.size(); i++)
512                                drawCross(&res, (int)ipts1[i].x, (int)ipts1[i].y);
513                        for (unsigned i = 0; i < ipts2.size(); i++)
514                                drawCross(&res, (int)ipts2[i].x, (int)ipts2[i].y + im1->getHeight());
515                }
516
517                ImageLoader.saveImage(ofname, &res);
518        }
519
520       
521        return 0;
522}
Note: See TracBrowser for help on using the repository browser.