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

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

Added original make3d

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