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

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

Added original make3d

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