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

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

Added original make3d

File size: 13.3 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 <iostream>
42#include <fstream>
43#include <cmath>
44
45#include "ipoint.h"
46
47
48#include "image.h"
49#include "imload.h"
50
51
52using namespace std;
53using namespace surf;
54
55// Length of descriptor vector, ugly, global variable
56unsigned int vlen;
57
58// Calculate square distance of two vectors
59double distSquare(double *v1, double *v2, int n) {
60        double dsq = 0.;
61        while (n--) {
62                dsq += (*v1 - *v2) * (*v1 - *v2);
63                v1++;
64                v2++;
65        }
66        return dsq;
67}
68
69// Find closest interest point in a list, given one interest point
70int findMatch(const Ipoint& ip1, const vector< Ipoint >& ipts) {
71        double mind = 1e100, second = 1e100; //Magic number Min??
72        int match = -1;
73
74        for (unsigned i = 0; i < ipts.size(); i++) {
75                // Take advantage of Laplacian to speed up matching
76                if (ipts[i].laplace != ip1.laplace)
77                        continue;
78
79                double d = distSquare(ipts[i].ivec, ip1.ivec, vlen);
80
81                if (d < mind) {
82                        second = mind;
83                        mind = d;
84                        match = i;
85                } else if (d < second) {
86                        second = d;
87                }
88        }
89
90        if (mind < 0.7 * second) //0.8 //Magic number Min??
91            //Answer: in SIFT paper 0.8 is used for discarding 90% of false match but discard only 5% of correct matches
92                return match;
93
94        return -1;
95}
96
97void printAllDistances(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2) {
98  for (unsigned int i = 0; i < ipts1.size(); i++) {
99    for (unsigned int j = 0; j < ipts2.size(); j++) {
100      double dist = distSquare(ipts1[i].ivec, ipts2[j].ivec, vlen);
101      cout << i << " " << j << " " << dist << endl;
102    }
103  }
104}
105
106//Min add ConstrainCheck to check if the Constrain been meet
107bool ConstrainCheck(const Ipoint& ipts1, const Ipoint& ipts2, const Ipoint& ConS1, const Ipoint& ConS2){
108
109//      cout << "test ConS1" << ConS1.ivec[1];
110//      cout << "test ConS2" << ConS2.ivec[1];
111       
112        bool Sat = false;
113        // check if ipts2 satisfy constrain1 or ipts1 satisfy constrain2
114        if (( ipts2.x >= ConS1.ivec[0] && ipts2.x <= ConS1.ivec[1] && ipts2.y >= ConS1.ivec[2] && ipts2.y <= ConS1.ivec[3]) || ( ipts1.x >= ConS2.ivec[0] && ipts1.x <= ConS2.ivec[1] && ipts1.y >= ConS2.ivec[2] && ipts1.y <= ConS2.ivec[3])){
115                Sat = true;
116//              cout << "violate satisfied";
117        }else{
118//              cout << "violate constrain";
119        }
120       
121        return Sat;       
122}
123
124// essentially the same as findMatches except that it deletes matches that
125// aren't symetric.
126// Really time-consuming function
127vector <int> symMatches(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2, const vector< Ipoint >& ConS1, const vector< Ipoint >& ConS2) {
128  vector< int > bestIndex1(ipts1.size());
129  vector< int > bestIndex2(ipts2.size());
130  vector< double > bestScore1(ipts1.size());
131  vector< double > bestScore2(ipts2.size());
132  vector< double > secondScore1(ipts1.size());
133  vector< double > secondScore2(ipts2.size());
134
135  // Initialize all of the vectors
136  for (unsigned int i = 0; i < ipts1.size(); i++) {
137    bestIndex1[i] = -1;
138    bestScore1[i]= 1e100;
139    secondScore1[i] = 1e100;
140  }
141  for (unsigned int j = 0; j < ipts2.size(); j++) {
142    bestIndex2[j] = -1;
143    bestScore2[j]= 1e100;
144    secondScore2[j] = 1e100;
145  }
146
147  // Main loop - per point in im1 do a linear scan of points in im2
148  int total = 0;
149  for (unsigned int i = 0; i < ipts1.size(); i++) {
150    for (unsigned int j = 0; j < ipts2.size(); j++) {
151       if (ipts1[i].laplace != ipts2[j].laplace)
152                        continue;
153        //Min add ConstrainCheck();
154        if ( !ConstrainCheck(ipts1[i], ipts2[j], ConS1[i], ConS2[j]))
155                        continue;
156
157        //record best and second best scores and best index for each
158      //point in each image
159      double dist = distSquare(ipts1[i].ivec, ipts2[j].ivec, vlen);
160      if (dist < bestScore1[i]) {
161        bestIndex1[i] = j;
162        secondScore1[i] = bestScore1[i];
163        bestScore1[i] = dist;
164      } else if (dist < secondScore1[i]) {
165        secondScore1[i] = dist;
166      }
167      if (dist < bestScore2[j]) {
168        bestIndex2[j] = i;
169        secondScore2[j] = bestScore2[j];
170        bestScore2[j] = dist;
171      } else if (dist < secondScore2[j]) {
172        secondScore2[j] = dist;
173      }
174    }
175  }
176  //cout << "Matched " << total << " points." << endl;
177  //return bestIndex1; //for threshold
178
179  /*******************************
180     //killed same img matches - should be covered by match symetry anyway
181 
182  //update second scores with best match from same image (for image 1)
183  for (int i = 0; i < ipts1.size(); i++) {
184    for (int j = i+1; j < ipts1.size(); j++) {
185      double dist = distSquare(ipts1[i].ivec, ipts1[j].ivec, vlen);
186      if (dist < secondScore1[i]){// && dist < 0.3) {
187        //cout << "im1 point " << i << " best: " << bestScore1[i] << " second: " << secondScore1[i] <<
188        //  "im1 point " << j << ": " << dist << endl;
189        secondScore1[i] = dist;
190      }
191    }
192  }
193
194  //update second scores with best match from same image (for image 2)
195  for (int i = 0; i < ipts2.size(); i++) {
196    for (int j = i+1; j < ipts2.size(); j++) {
197      double dist = distSquare(ipts2[i].ivec, ipts2[j].ivec, vlen);
198      if (dist < secondScore2[j]){// && dist < 0.3){
199        //cout << "im2 point " << i << " best: " << bestScore2[i] << " second: " << secondScore2[i] <<
200        //  "im2 point " << j << ": " << dist << endl;
201        secondScore2[i] = dist;
202      }
203    }
204  }
205  ******************************/
206
207  //if the best score is no longer the best or isn't good enough relative
208  // to the second, kill the index
209
210  //image 1 //Min change 0.85 to 0.7
211  for (unsigned int i = 0; i < ipts1.size(); i++) {
212    if (secondScore1[i] * 0.7 < bestScore1[i]) {
213      bestIndex1[i] = -1;
214    }
215  }
216
217  //image 2 //Min change 0.85 to 0.7
218  for (unsigned int i = 0; i < ipts2.size(); i++) {
219    if (secondScore2[i] * 0.7 < bestScore2[i]) {
220      bestIndex2[i] = -1;
221    }
222  }
223
224  //if the best matches aren't mutual, kill the match
225  for (unsigned int i = 0; i < ipts1.size(); i++) {
226    int index = bestIndex1[i];
227    if (index != -1) {
228      if (bestIndex2[index] != i) {
229        //cout << "Non symetric match.  im1(" << i << ")->" << index << " but im2(" << index <<
230        //  ")->" << bestIndex2[index] << endl;
231        bestIndex1[i] = -1;
232      } else {
233        cout << " Matched feature " << i << " in image 1 with feature "
234             << index << " in image 2." << endl;
235        total++;
236      }
237    }
238  }
239
240  cout << "Matched " << total << " points." << endl;
241  return bestIndex1;
242}
243
244// Find all possible matches between two images
245// need to change to reduce the search space by knowing GPS information Min
246vector< int > findMatches(const vector< Ipoint >& ipts1, const vector< Ipoint >& ipts2) {
247        vector< int > matches(ipts1.size());
248        int c = 0;
249        for (unsigned i = 0; i < ipts1.size(); i++) {
250                int match = findMatch(ipts1[i], ipts2);
251                matches[i] = match;
252                if (match != -1) {
253                        cout << " Matched feature " << i << " in image 1 with feature "
254                                << match << " in image 2." << endl;
255                        c++;
256                }
257        }
258        cout << " --> Matched " << c << " features of " << ipts1.size() << " in image 1." << endl;
259        return matches;
260}
261
262// Load the interest points from a regular ASCII file
263void loadIpoints(string sFileName, vector< Ipoint >& ipts) {
264        ifstream ipfile(sFileName.c_str());
265        if( !ipfile ) {
266                cerr << "ERROR in loadIpoints(): "
267                        << "Couldn't open file '" << sFileName.c_str() << "'!" << endl;
268                return;
269        }
270
271        // Load the file header
272        unsigned count;
273        ipfile >> vlen >> count;
274
275        // create a new interest point vector
276        ipts.clear();
277        ipts.resize(count);
278        //cout << "The number of features" << count << endl;
279
280        // Load the interest points in Mikolajczyk's format
281        for (unsigned n = 0; n < count; n++) {
282                // circular regions with diameter 5 x scale
283                float x, y, a, b, c;
284
285                // Read in region data, though not needed for actual matching
286                ipfile >> x >> y >> a >> b >> c;
287
288                float det = sqrt((a-c)*(a-c) + 4.0*b*b);
289                float e1 = 0.5*(a+c + det);
290                float e2 = 0.5*(a+c - det);
291                float l1 = (1.0/sqrt(e1));
292                float l2 = (1.0/sqrt(e2));
293                float sc = sqrt( l1*l2 );
294
295                ipts[n].x = x;
296                ipts[n].y = y;
297                ipts[n].scale = sc/2.5;
298
299                // Read in Laplacian
300                ipfile >> ipts[n].laplace;
301
302                // SURF makes Laplacian part of descriptor, so skip it..
303                ipts[n].ivec = new double[vlen - 1];
304                for (unsigned j = 0; j < vlen - 1; j++)
305                        ipfile >> ipts[n].ivec[j];
306        }
307}
308
309void drawLine(Image *im, int x1, int y1, int x2, int y2) {
310        if ((x1 < 0 && x2 < 0) || (y1 < 0 && y2 < 0) ||
311            (x1 >= im->getWidth() && x2 >= im->getWidth()) ||
312            (y1 >= im->getHeight() && y2 >= im->getHeight()))
313                return;
314
315        bool steep = std::abs(y2 - y1) > std::abs(x2 - x1);
316        if (steep) {
317                int t;
318                t = x1;
319                x1 = y1;
320                y1 = t;
321                t = y2;
322                y2 = x2;
323                x2 = t;
324        }
325
326        if (x1 > x2) {
327                // Swap points
328                int t;
329                t = x1;
330                x1 = x2;
331                x2 = t;
332                t = y1;
333                y1 = y2;
334                y2 = t;
335        }
336
337        int deltax = x2 - x1;
338        int deltay = std::abs(y2 - y1);
339
340        int error = 0;
341        int y = y1;
342        int ystep = y1 < y2 ? 1 : -1;
343
344        for (int x = x1; x < x2; x++) {
345                if (steep) {
346                        if (x >= 0 && y >= 0 && y < im->getWidth() && x < im->getHeight())
347                                im->setPix(y, x, 1);
348                } else {
349                        if (x >= 0 && y >= 0 && x < im->getWidth() && y < im->getHeight())
350                                im->setPix(x, y, 1);
351
352                }
353                error += deltay;
354
355                if (2 * error > deltax) {
356                        y += ystep;
357                        error -= deltax;
358                }
359        }
360}
361
362void drawCross(Image *im, int x, int y, int s = 5) {
363        for (int x1 = x - s; x1 <= x + s; x1++)
364                im->setPix(x1, y, 1);
365        for (int y1 = y - s; y1 <= y + s; y1++)
366                im->setPix(x, y1, 1);
367}
368
369int main(int argc, char **argv) {
370        Image *im1, *im2;
371
372        ImLoad ImageLoader;
373        vector< Ipoint > ipts1, ipts2, ConS1, ConS2; //Min
374        bool drawc = false;
375        bool usesym = false;
376        bool printAllDist = false;
377
378        char ofname[100];
379
380        im1 = im2 = NULL;
381        ofname[0] = 0;
382
383        // Read the arguments
384        int arg = 0;
385        while (++arg < argc) { 
386                if (! strcmp(argv[arg], "-k1"))
387                        loadIpoints(argv[++arg], ipts1);
388                if (! strcmp(argv[arg], "-k2"))
389                        loadIpoints(argv[++arg], ipts2);
390                //Min -------------------------------------
391                if (! strcmp(argv[arg], "-S1")) 
392                        loadIpoints(argv[++arg], ConS1);
393                if (! strcmp(argv[arg], "-S2"))
394                        loadIpoints(argv[++arg], ConS2);
395                //Min -------------------------------------
396
397                if (! strcmp(argv[arg], "-im1"))
398                        im1 = ImageLoader.readImage(argv[++arg]); 
399                if (! strcmp(argv[arg], "-im2"))
400                        im2 = ImageLoader.readImage(argv[++arg]); 
401                if (! strcmp(argv[arg], "-o"))
402                        strcpy(ofname, argv[++arg]);
403                if (! strcmp(argv[arg], "-c"))
404                        drawc = true;
405                if (! strcmp(argv[arg], "-s"))
406                        usesym = true;
407                if (! strcmp(argv[arg], "-d"))
408                        printAllDist = true;
409
410        }
411
412        if (ipts1.size() == 0 || ipts2.size() == 0) {
413                cout << "Usage:" << endl;
414                cout << " match [-s] -k1 out1.surf -k2 out2.surf -im1 img1.pgm -im2 img2.pgm -o out.pgm" << endl << endl;
415                cout << "For each feature in first descriptor file, find best in second according to "
416                        << "nearest neighbor ratio strategy. Display matches in out.pgm, generated "
417                        << "from img1.pgm and img2.pgm. Use -c to draw crosses at interest points." << endl;
418
419                cout << "use -s to require that the best match be symetric."<<endl;
420                cout << "use -d to print out all of the n*m distances between points instead of matching."<<endl;
421                return 1;
422        }
423
424        vector< int > matches;
425         
426        if (usesym) {
427          cerr << "Using symmetricConS matches, using descriptor length " << vlen << ConS1[0].ivec[3] << endl;
428//        cout << "test CONS" << ConS1[1].ivec[1] << endl;
429                matches = symMatches(ipts1, ipts2, ConS1, ConS2);//Min
430        } else if (printAllDist){
431          printAllDistances(ipts1, ipts2);
432        } else {
433          matches = findMatches(ipts1, ipts2);
434        }
435
436
437        if (im1 != NULL && im2 != NULL && ofname[0] != 0) {
438                Image res(max(im1->getWidth(), im2->getWidth()), im1->getHeight() + im2->getHeight());
439                for (int x = 0; x < im1->getWidth(); x++)
440                        for (int y = 0; y < im1->getHeight(); y++)
441                                res.setPix(x, y, im1->getPix(x, y));
442                for (int x = 0; x < im2->getWidth(); x++)
443                        for (int y = 0; y < im2->getHeight(); y++)
444                                res.setPix(x, y + im1->getHeight(), im2->getPix(x, y));
445
446                // Draw lines for matches
447                for (unsigned i = 0; i < matches.size(); i++) {
448                        if (matches[i] != -1) {
449                                drawLine(&res, (int)ipts1[i].x, (int)ipts1[i].y,
450                                        (int)ipts2[matches[i]].x, (int)(ipts2[matches[i]].y + im1->getHeight()));
451                        }
452                }
453
454                // Draw crosses at interest point locations
455                if (drawc) {
456                        for (unsigned i = 0; i < ipts1.size(); i++)
457                                drawCross(&res, (int)ipts1[i].x, (int)ipts1[i].y);
458                        for (unsigned i = 0; i < ipts2.size(); i++)
459                                drawCross(&res, (int)ipts2[i].x, (int)ipts2[i].y + im1->getHeight());
460                }
461
462                ImageLoader.saveImage(ofname, &res);
463        }
464
465       
466        return 0;
467}
Note: See TracBrowser for help on using the repository browser.