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

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

Added original make3d

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