BaxterInterface/ASIFT_tests/demo_ASIFT_src/orsa.cpp
2018-07-23 17:30:57 +02:00

592 lines
16 KiB
C++
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// C++ Implementation: stereomatch
//
// Description: eliminate the false matches with epipolar geometry constraint.
// See http://www.math-info.univ-paris5.fr/~moisan/epipolar/
//
// Copyright (c) 2007 Lionel Moisan <Lionel.Moisan@parisdescartes.fr>
// Changelog : 2011 Use Eigen SVD <Pierre Moulon>
//
// Copyright: See COPYING file that comes with this distribution
//
//
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include "orsa.h"
#include <third_party/Eigen/Cholesky>
#include <third_party/Eigen/Core>
#include <third_party/Eigen/Eigenvalues>
#include <third_party/Eigen/LU>
#include <third_party/Eigen/QR>
#include <third_party/Eigen/SVD>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/*-------------------- GENERAL PURPOSE ROUTINES --------------------*/
/* routines for vectors and matrices */
float *vector(int nl, int nh)
{
float *v;
v=(float *)malloc((unsigned) (nh-nl+1)*sizeof(float));
if (!v) {
// mwerror(FATAL,1,"allocation failure in vector()");
fprintf(stderr, "allocation failure in vector()\n");
exit(EXIT_FAILURE); /* indicate failure.*/
}
return v-nl;
}
float **matrix(int nrl, int nrh, int ncl, int nch)
{
int i;
float **m;
m=(float **) malloc((unsigned) (nrh-nrl+1)*sizeof(float*));
if (!m) {
// mwerror(FATAL,1,"allocation failure 1 in matrix()");
fprintf(stderr, "allocation failure 1 in matrix()\n");
exit(EXIT_FAILURE); /* indicate failure.*/
}
m -= nrl;
for(i=nrl;i<=nrh;i++) {
m[i]=(float *) malloc((unsigned) (nch-ncl+1)*sizeof(float));
if (!m[i]) {
// mwerror(FATAL,1,"allocation failure 2 in matrix()");
fprintf(stderr, "allocation failure 2 in matrix()\n");
exit(EXIT_FAILURE); /* indicate failure.*/
}
m[i] -= ncl;
}
return m;
}
void free_vector(float *v, int nl, int nh)
{
free((char*) (v+nl));
nh = nh; // to remove the warning "unused parameter nh"
}
void free_matrix(float **m, int nrl, int nrh, int ncl, int nch)
{
int i;
for(i=nrh;i>=nrl;i--) free((char*) (m[i]+ncl));
free((char*) (m+nrl));
nch = nch; // to remove the warning "unused parameter nh"
}
/* Compute the real roots of a third order polynomial */
/* returns 1 or 3, the number of roots found */
int FindCubicRoots(float coeff[4], float x[3])
{
float a1 = coeff[2] / coeff[3];
float a2 = coeff[1] / coeff[3];
float a3 = coeff[0] / coeff[3];
double Q = (a1 * a1 - 3 * a2) / 9;
double R = (2 * a1 * a1 * a1 - 9 * a1 * a2 + 27 * a3) / 54;
double Qcubed = Q * Q * Q;
double d = Qcubed - R * R;
/* Three real roots */
if (d >= 0) {
double theta = acos(R / sqrt(Qcubed));
double sqrtQ = sqrt(Q);
x[0] = -2 * sqrtQ * cos( theta / 3) - a1 / 3;
x[1] = -2 * sqrtQ * cos((theta + 2 * M_PI) / 3) - a1 / 3;
x[2] = -2 * sqrtQ * cos((theta + 4 * M_PI) / 3) - a1 / 3;
return (3);
}
/* One real root */
else {
double e = pow(sqrt(-d) + fabs(R), 1. / 3.);
if (R > 0)
e = -e;
x[0] = (e + Q / e) - a1 / 3.;
return (1);
}
}
/* logarithm (base 10) of binomial coefficient */
float logcombi(int k, int n)
{
double r;
int i;
if (k>=n || k<=0) return(0.);
if (n-k<k) k=n-k;
r = 0.;
for (i=1;i<=k;i++)
r += log10((double)(n-i+1))-log10((double)i);
return((float)r);
}
/* tabulate logcombi(.,n) */
float *makelogcombi_n(int n)
{
float *l;
int k;
l = (float *)malloc((n+1)*sizeof(float));
for (k=0;k<=n;k++) l[k]=logcombi(k,n);
return(l);
}
/* tabulate logcombi(k,.) */
float *makelogcombi_k(int k, int nmax)
{
float *l;
int n;
l = (float *)malloc((nmax+1)*sizeof(float));
for (n=0;n<=nmax;n++) l[n]=logcombi(k,n);
return(l);
}
/* get a (sorted) random 7-uple of 0..n-1 */
void random_p7(int *k, int n)
{
int i,j,j0,r;
for (i=0;i<7;i++) {
r = (rand()>>3)%(n-i);
for (j=0;j<i && r>=k[j];j++) r++;
j0 = j;
for (j=i;j>j0;j--) k[j]=k[j-1];
k[j0]=r;
}
}
/*-------------------- END OF GENERAL PURPOSE ROUTINES --------------------*/
/* float comparison for qsort() */
//According to http://www.cplusplus.com/reference/clibrary/cstdlib/qsort/,
//we should have: void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) ); that means, for "qsort", the "comparator" has two constant void* type input parameters
// static int compf(void *i, void *j)
int compf(const void *i, const void *j)
{
float a,b;
a = *((float *)i);
b = *((float *)j);
return(a<b?-1:(a>b?1:0));
}
/* find the increasing sequence of squared distances to epipolar lines */
/* e[n*2] = distances, e[n*2+1] = indexes (to cast into an int) */
//void matcherrorn(float **F, Flist p1, Flist p2, float *e)
void matcherrorn(float **F, const std::vector<float>& p1, const std::vector<float>& p2, float *e)
{
int i;
double x,y,a,b,c,d; // Guoshen Yu, double precision is needed. When the two images are identical, the error under float precision is 0 => log(error)=-inf.
int pt_size = (p1.size())/2;
for (i = 0; i < pt_size; i++) {
x = (double) p1[i*2];
y = (double) p1[i*2+1];
a = (double) F[1][1]*x+(double) F[1][2]*y+(double) F[1][3];
b = (double) F[2][1]*x+(double) F[2][2]*y+(double) F[2][3];
c = (double) F[3][1]*x+(double) F[3][2]*y+(double) F[3][3];
d = (a*(double) p2[i*2]+b*(double) p2[i*2+1]+c);
e[i*2] = (d*d)/(a*a+b*b);
e[i*2+1] = (float)i;
}
qsort(e, pt_size, 2*sizeof(float), compf);
}
/*---------- compute the epipolar geometry associated to 7 pairs ----------*/
/* */
/* INPUT: the points are (m1[k[i]*2],m1[k[i]*2+1]), m2... 0<i<7 */
/* */
/* OUTPUT: */
/* return the number of roots found, stored in z[] */
/* the epipolar matrices are F1[i][j]+z[k]*F2[i][j], 1<=i,j<=3, 0<=k<m */
// int epipolar(float *m1, float *m2, int *k, float *z, float **F1, float **F2)
int epipolar(std::vector<float>& m1, std::vector<float>& m2, int *k, float *z, float **F1, float **F2)
{
float a[4];
int i,j,i2,i3;
typedef Eigen::MatrixXf Mat;
Mat c(7,9);
/* build 9xn matrix from point matches */
for (i=0;i<7;i++) {
c(i,0) = m1[k[i]*2 ]*m2[k[i]*2 ];
c(i,1) = m1[k[i]*2+1]*m2[k[i]*2 ];
c(i,2) = m2[k[i]*2 ];
c(i,3) = m1[k[i]*2 ]*m2[k[i]*2+1];
c(i,4) = m1[k[i]*2+1]*m2[k[i]*2+1];
c(i,5) = m2[k[i]*2+1];
c(i,6) = m1[k[i]*2 ];
c(i,7) = m1[k[i]*2+1];
c(i,8) = 1.;
}
// SVD
Eigen::JacobiSVD<Mat> svd(c, Eigen::ComputeFullV);
// look for the two smallest eigenvalue of c'c
typedef Eigen::Matrix<float, 9, 1> Vec9;
Vec9 F1Vec = svd.matrixV().col(c.cols()-1);
Vec9 F2Vec = svd.matrixV().col(c.cols()-2);
/* build basis of solutions */
int cpt = 0;
for (i=1;i<=3;i++)
for (j=1;j<=3;j++)
{
F1[i][j] = F1Vec(cpt);
F2[i][j] = F2Vec(cpt);
cpt++;
}
/* build cubic polynomial P(x)=det(F1+xF2) */
a[0] = a[1] = a[2] = a[3] = 0.;
for (i=1;i<=3;i++) {
i2 = i%3+1;
i3 = i2%3+1;
a[0] += F1[i][1]*F1[i2][2]*F1[i3][3];
a[1] +=
F2[i][1]*F1[i2][2]*F1[i3][3]+
F1[i][1]*F2[i2][2]*F1[i3][3]+
F1[i][1]*F1[i2][2]*F2[i3][3];
a[2] +=
F1[i][1]*F2[i2][2]*F2[i3][3]+
F2[i][1]*F1[i2][2]*F2[i3][3]+
F2[i][1]*F2[i2][2]*F1[i3][3];
a[3] += F2[i][1]*F2[i2][2]*F2[i3][3];
}
for (i=1;i<=3;i++) {
i2 = (i+1)%3+1;
i3 = (i2+1)%3+1;
a[0] -= F1[i][1]*F1[i2][2]*F1[i3][3];
a[1] -=
F2[i][1]*F1[i2][2]*F1[i3][3]+
F1[i][1]*F2[i2][2]*F1[i3][3]+
F1[i][1]*F1[i2][2]*F2[i3][3];
a[2] -=
F1[i][1]*F2[i2][2]*F2[i3][3]+
F2[i][1]*F1[i2][2]*F2[i3][3]+
F2[i][1]*F2[i2][2]*F1[i3][3];
a[3] -= F2[i][1]*F2[i2][2]*F2[i3][3];
}
return(FindCubicRoots(a,z));
}
void divide_match(const std::vector<Match>& matches, std::vector<float>& p1, std::vector<float>& p2)
{
float x1, y1, x2, y2;
p1.clear();
p2.clear();
p1.reserve(2 * matches.size());
p2.reserve(2 * matches.size());
std::vector<Match>::const_iterator it=matches.begin();
for(; it != matches.end(); ++it) {
x1 = (*it).x1; y1 = (*it).y1;
x2 = (*it).x2; y2 = (*it).y2;
p1.push_back(x1); p1.push_back(y1);
p2.push_back(x2); p2.push_back(y2);
}
}
// float stereomatch(int img_x, int img_y, int size_pt, float* p1, float* p2, float** f, float* index, int* t, int* verb, int* n_flag, int* mode, int* stop)
// float stereomatch(const wxImage& u1, std::vector<float>& p1, std::vector<float>& p2, std::vector<SmallVector<float,3> >& f, std::vector<float>& index, int* t, int* verb, int* n_flag, int* mode, int* stop)
//int main(int argc, char** argv)
float orsa(int width, int height, std::vector<Match>& match, std::vector<float>& index, int t_value, int verb_value, int n_flag_value, int mode_value, int stop_value)
{
// int width = 0, height = 0;
// int t_value, verb_value, n_flag_value, mode_value, stop_value;
int *t, *verb, *n_flag, *mode, *stop;
t = (int*)malloc(sizeof(int)); // maximum number of ransac trials
verb = (int*)malloc(sizeof(int)); //verbose
n_flag = (int*)malloc(sizeof(int)); // in order NOT to reinitialize the random seed
mode = (int*)malloc(sizeof(int)); // mode: 0=deterministic 1=ransac 2=optimized ransac (ORSA) 3=automatic
stop = (int*)malloc(sizeof(int)); // stop as soon as the first meaningful correspondence is found
if(width <=0 || height <= 0) {
std::cerr << "Wrong dimensions of image" << std::endl;
return 1;
}
std::vector<float> p1(2*match.size()), p2(2*match.size()), p1_backup(2*match.size()), p2_backup(2*match.size());
divide_match(match, p1, p2);
p1_backup = p1;
p2_backup = p2;
libNumerics::matrix<libNumerics::flnum> f(3, 3);
f = 0;
index = std::vector<float>(match.size());
// Guoshen Yu, 2010.09.23
// index.clear();
if(t_value <= 0) {
std::cerr << "t should be greater than 0" << std::endl;
return 1;
}
*t = t_value;
if(verb_value == 0) {
free(verb);
verb = NULL;
}
else
*verb = verb_value;
if(verb_value != 1 && verb_value != 0) {
std::cerr << "verb can only be 0 or 1" << std::endl;
return 1;
}
if(n_flag_value == 0) {
free(n_flag);
n_flag = NULL;
}
else
*n_flag = n_flag_value;
if(n_flag_value != 1 && n_flag_value != 0) {
std::cerr << "n_flag can only be 0 or 1" << std::endl;
return 1;
}
if(mode_value != 0 && mode_value != 1 && mode_value != 2 && mode_value != 3) {
std::cerr << "mode can only be 0 or 1 or 2 or 3" << std::endl;
return 1;
}
*mode = mode_value;
if(stop_value == 0) {
free(stop);
stop = NULL;
}
else
*stop = stop_value;
if(stop_value != 1 && stop_value != 0) {
std::cerr << "stop can only be 0 or 1" << std::endl;
return 1;
}
int i,j,i0,k[8],idk[8],*id,m,n,l,minicur=0,miniall=0,delete_index,nid;
int niter,maxniter,better,cont,optimization;
float **F1,**F2,**F,nx,ny,z[3],minepscur,minepsall,nfa;
float norm,minlogalphacur,minlogalphaall,logalpha,logalpha0;
float *e,*logcn,*logc7,loge0;
/* initialize random seed if necessary */
// if (!n_flag) srand48( (long int) time (NULL) + (long int) getpid() );
// if (!n_flag) srand( (long int) time (NULL) + (long int) getpid() );
// Guoshen Yu, 2010.09.21: remove getpid which does not exist under Windows
if (!n_flag) srand( (long int) time (NULL) );
/* check sizes */
if (p1.size() != p2.size() || p1.size() < 14) {
fprintf(stderr, "Inconsistent sizes.\n");
exit(EXIT_FAILURE); /* indicate failure.*/
}
n = p1.size()/2;
/* tabulate logcombi */
loge0 = (float)log10(3.*(double)(n-7));
logcn = makelogcombi_n(n);
logc7 = makelogcombi_k(7,n);
/* choose mode */
if (*mode==3) {
if (logcn[7]<=(float)log10((double)(*t)))
*mode=0;
else *mode=2;
}
if (verb)
switch(*mode) {
case 0:
// i = (int)(0.5+pow(10.,logc7[n]));
// Guoshen Yu, 2010.09.22, Windows version
i = (int)(0.5+pow(10., (double)(logc7[n])));
printf("I will use deterministic mode (systematic search).\n");
printf("I have to test %d bases\n",i);
break;
case 1:
printf("I will use pure stochastic mode with no optimization.\n");
break;
case 2:
printf("I will use optimized stochastic mode (ORSA).\n");
}
/* normalize coordinates */
nx = (float)width;
ny = (float)height;
norm = 1./(float)sqrt((double)(nx*ny));
logalpha0 = (float)(log10(2.)+0.5*log10((double)((nx*nx+ny*ny)*norm*norm)));
for (i=0;i<n;i++) {
p1[i*2 ] = (p1[i*2 ]-0.5*nx)*norm;
p1[i*2+1] = (p1[i*2+1]-0.5*ny)*norm;
p2[i*2 ] = (p2[i*2 ]-0.5*nx)*norm;
p2[i*2+1] = (p2[i*2+1]-0.5*ny)*norm;
}
/* allocate and initialize memory */
F = matrix(1,3,1,3);
F1 = matrix(1,3,1,3);
F2 = matrix(1,3,1,3);
//delete_index = (index?0:1);
delete_index = 0;
e = (float *)malloc(2*n*sizeof(float));
id = (int *)malloc(n*sizeof(int));
for (i=0;i<n;i++) id[i]=i;
nid = n;
maxniter = (*mode==0?*t:*t-(*t)/10);
minlogalphaall = minepsall = 10000.;
niter = optimization = 0;
i0=0; k[0]=-1; k[7]=n;
/********** MAIN LOOP **********/
do {
niter++;
/* build next list of points */
if (*mode) random_p7(k,nid);
else {
k[i0]++;
for (i=i0+1;i<=6;i++) k[i]=k[i-1]+1;
}
for (i=0;i<7;i++) idk[i]=id[k[i]];
/* find epipolar transform */
m = epipolar(p1,p2,idk,z,F1,F2);
/* loop on roots */
for (;m--;) {
for (i=1;i<=3;i++)
for (j=1;j<=3;j++)
F[i][j] = F1[i][j]+z[m]*F2[i][j];
/* sort errors */
matcherrorn(F,p1,p2,e);
/* find most meaningful subset */
minepscur = minlogalphacur = 10000.;
for (i=7;i<n;i++) {
logalpha = logalpha0+0.5*(float)log10((double)e[i*2]);
nfa = loge0+logalpha*(float)(i-6)+logcn[i+1]+logc7[i+1];
if (nfa<minepscur) {
minepscur = nfa;
minicur = i;
minlogalphacur = logalpha;
}
}
if (minepscur<minepsall) {
/* store best result so far */
better = 1;
minepsall = minepscur;
minlogalphaall = minlogalphacur;
miniall = minicur;
// if (f)
for (l=1;l<=3;l++)
for (j=1;j<=3;j++)
f(l-1, j-1) = F[l][j];
// Guoshen Yu, 2010.09.22
// for (i=0;i<=minicur;i++)
for (i=0;i<minicur;i++)
{
index[i] = e[i*2+1];
}
} else better=0;
if (*mode==2 && ((better && minepsall<0.) ||
(niter==maxniter && !optimization))) {
if (!optimization) maxniter = niter + (*t)/10;
optimization = 1;
/* final optimization */
if (verb) {
printf(" nfa=%f size=%d (niter=%d)\n",minepsall,miniall+1,niter);
printf("optimization...\n");
}
nid = miniall+1;
// Guoshen Yu, 2010.09.22
// for (j=0;j<=miniall;j++)
for (j=0;j<miniall;j++)
id[j] = (int)(index[j]);
}
}
/* prepare next list of points */
if (*mode==0)
for(i0=6;i0>=0 && k[i0]==k[i0+1]-1;i0--){};
if (stop && minepsall<0.) cont=0;
else if (*mode==0) cont=(i0>=0?1:0);
else cont=(niter<maxniter?1:0);
} while (cont);
//erase "index", only get the index of the meaningful matchings
index.erase(index.begin()+miniall+1, index.end());
if (verb)
printf("best matching found: %d points log(alpha)=%f (%d iterations)\n",
miniall+1,minlogalphaall,niter);
/* free memory */
free(id);
free(e);
// if (delete_index) mw_delete_flist(index);
free_matrix(F2,1,3,1,3);
free_matrix(F1,1,3,1,3);
free_matrix(F,1,3,1,3);
free(logc7);
free(logcn);
if(t) free(t);
if(verb) free(verb);
if(n_flag) free(n_flag);
if(mode) free(mode);
if(stop) free(stop);
// return 0;
return(minepsall);
}