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

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

Added original make3d

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