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

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

Added original make3d

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