00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "viso_stereo.h"
00023
00024 using namespace std;
00025
00026 VisualOdometryStereo::VisualOdometryStereo (parameters param) : param(param), VisualOdometry(param) {
00027 }
00028
00029 VisualOdometryStereo::~VisualOdometryStereo() {
00030 }
00031
00032 bool VisualOdometryStereo::process (uint8_t *I1,uint8_t *I2,int32_t* dims,bool replace) {
00033 matcher->pushBack(I1,I2,dims,replace);
00034 matcher->matchFeatures(2);
00035 matcher->bucketFeatures(param.bucket.max_features,param.bucket.bucket_width,param.bucket.bucket_height);
00036 p_matched = matcher->getMatches();
00037 return updateMotion();
00038 }
00039
00040 vector<double> VisualOdometryStereo::estimateMotion (vector<Matcher::p_match> p_matched) {
00041
00042
00043 bool success = true;
00044
00045
00046 double width=0,height=0;
00047 for (vector<Matcher::p_match>::iterator it=p_matched.begin(); it!=p_matched.end(); it++) {
00048 if (it->u1c>width) width = it->u1c;
00049 if (it->v1c>height) height = it->v1c;
00050 }
00051 double min_dist = min(width,height)/3.0;
00052
00053
00054 int32_t N = p_matched.size();
00055 if (N<6)
00056 return vector<double>();
00057
00058
00059 X = new double[N];
00060 Y = new double[N];
00061 Z = new double[N];
00062 J = new double[4*N*6];
00063 p_predict = new double[4*N];
00064 p_observe = new double[4*N];
00065 p_residual = new double[4*N];
00066
00067
00068 for (int32_t i=0; i<N; i++) {
00069 double d = max(p_matched[i].u1p - p_matched[i].u2p,1.0f);
00070 X[i] = (p_matched[i].u1p-param.calib.cu)*param.base/d;
00071 Y[i] = (p_matched[i].v1p-param.calib.cv)*param.base/d;
00072 Z[i] = param.calib.f*param.base/d;
00073 }
00074
00075
00076 vector<double> tr_delta;
00077 vector<double> tr_delta_curr;
00078 tr_delta_curr.resize(6);
00079
00080
00081 inliers.clear();
00082
00083
00084 for (int32_t k=0;k<param.ransac_iters;k++) {
00085
00086
00087 vector<int32_t> active = getRandomSample(N,3);
00088
00089
00090 for (int32_t i=0; i<6; i++)
00091 tr_delta_curr[i] = 0;
00092
00093
00094 VisualOdometryStereo::result result = UPDATED;
00095 int32_t iter=0;
00096 while (result==UPDATED) {
00097 result = updateParameters(p_matched,active,tr_delta_curr,1,1e-6);
00098 if (iter++ > 20 || result==CONVERGED)
00099 break;
00100 }
00101
00102
00103 if (result!=FAILED) {
00104 vector<int32_t> inliers_curr = getInlier(p_matched,tr_delta_curr);
00105 if (inliers_curr.size()>inliers.size()) {
00106 inliers = inliers_curr;
00107 tr_delta = tr_delta_curr;
00108 }
00109 }
00110 }
00111
00112
00113 if (inliers.size()>=6) {
00114 int32_t iter=0;
00115 VisualOdometryStereo::result result = UPDATED;
00116 while (result==UPDATED) {
00117 result = updateParameters(p_matched,inliers,tr_delta,1,1e-8);
00118 if (iter++ > 100 || result==CONVERGED)
00119 break;
00120 }
00121
00122
00123 if (result!=CONVERGED)
00124 success = false;
00125
00126
00127 } else {
00128 success = false;
00129 }
00130
00131
00132 delete X;
00133 delete Y;
00134 delete Z;
00135 delete J;
00136 delete p_predict;
00137 delete p_observe;
00138 delete p_residual;
00139
00140
00141 if (success) return tr_delta;
00142 else return vector<double>();
00143 }
00144
00145 vector<int32_t> VisualOdometryStereo::getInlier(vector<Matcher::p_match> &p_matched,vector<double> &tr) {
00146
00147
00148 vector<int32_t> active;
00149 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00150 active.push_back(i);
00151
00152
00153 computeObservations(p_matched,active);
00154 computeResidualsAndJacobian(tr,active);
00155
00156
00157 vector<int32_t> inliers;
00158 for (int32_t i=0; i<(int32_t)p_matched.size(); i++)
00159 if (pow(p_observe[4*i+0]-p_predict[4*i+0],2)+pow(p_observe[4*i+1]-p_predict[4*i+1],2) +
00160 pow(p_observe[4*i+2]-p_predict[4*i+2],2)+pow(p_observe[4*i+3]-p_predict[4*i+3],2) < param.inlier_threshold*param.inlier_threshold)
00161 inliers.push_back(i);
00162 return inliers;
00163 }
00164
00165 VisualOdometryStereo::result VisualOdometryStereo::updateParameters(vector<Matcher::p_match> &p_matched,vector<int32_t> &active,vector<double> &tr,double step_size,double eps) {
00166
00167
00168 if (active.size()<3)
00169 return FAILED;
00170
00171
00172 computeObservations(p_matched,active);
00173 computeResidualsAndJacobian(tr,active);
00174
00175
00176 Matrix A(6,6);
00177 Matrix B(6,1);
00178
00179
00180 for (int32_t m=0; m<6; m++) {
00181 for (int32_t n=0; n<6; n++) {
00182 double a = 0;
00183 for (int32_t i=0; i<4*(int32_t)active.size(); i++) {
00184 a += J[i*6+m]*J[i*6+n];
00185 }
00186 A.val[m][n] = a;
00187 }
00188 double b = 0;
00189 for (int32_t i=0; i<4*(int32_t)active.size(); i++) {
00190 b += J[i*6+m]*(p_residual[i]);
00191 }
00192 B.val[m][0] = b;
00193 }
00194
00195
00196 if (B.solve(A)) {
00197 bool converged = true;
00198 for (int32_t m=0; m<6; m++) {
00199 tr[m] += step_size*B.val[m][0];
00200 if (fabs(B.val[m][0])>eps)
00201 converged = false;
00202 }
00203 if (converged)
00204 return CONVERGED;
00205 else
00206 return UPDATED;
00207 } else {
00208 return FAILED;
00209 }
00210 }
00211
00212 void VisualOdometryStereo::computeObservations(vector<Matcher::p_match> &p_matched,vector<int32_t> &active) {
00213
00214
00215 for (int32_t i=0; i<(int32_t)active.size(); i++) {
00216 p_observe[4*i+0] = p_matched[active[i]].u1c;
00217 p_observe[4*i+1] = p_matched[active[i]].v1c;
00218 p_observe[4*i+2] = p_matched[active[i]].u2c;
00219 p_observe[4*i+3] = p_matched[active[i]].v2c;
00220 }
00221 }
00222
00223 void VisualOdometryStereo::computeResidualsAndJacobian(vector<double> &tr,vector<int32_t> &active) {
00224
00225
00226 double rx = tr[0]; double ry = tr[1]; double rz = tr[2];
00227 double tx = tr[3]; double ty = tr[4]; double tz = tr[5];
00228
00229
00230 double sx = sin(rx); double cx = cos(rx); double sy = sin(ry);
00231 double cy = cos(ry); double sz = sin(rz); double cz = cos(rz);
00232
00233
00234 double r00 = +cy*cz; double r01 = -cy*sz; double r02 = +sy;
00235 double r10 = +sx*sy*cz+cx*sz; double r11 = -sx*sy*sz+cx*cz; double r12 = -sx*cy;
00236 double r20 = -cx*sy*cz+sx*sz; double r21 = +cx*sy*sz+sx*cz; double r22 = +cx*cy;
00237 double rdrx10 = +cx*sy*cz-sx*sz; double rdrx11 = -cx*sy*sz-sx*sz; double rdrx12 = -cx*cy;
00238 double rdrx20 = +sx*sy*cz+cx*sz; double rdrx21 = -sx*sy*sz+cx*cz; double rdrx22 = -sx*cy;
00239 double rdry00 = -sy*cz; double rdry01 = +sy*sz; double rdry02 = +cy;
00240 double rdry10 = +sx*cy*cz; double rdry11 = -sx*cy*sz; double rdry12 = +sx*sy;
00241 double rdry20 = -cx*cy*cz; double rdry21 = +cx*cy*sz; double rdry22 = -cx*sy;
00242 double rdrz00 = -cy*sz; double rdrz01 = -cy*cz;
00243 double rdrz10 = -sx*sy*sz+cx*cz; double rdrz11 = -sx*sy*cz-cx*sz;
00244 double rdrz20 = +cx*sy*sz+sx*cz; double rdrz21 = +cx*sy*cz-sx*sz;
00245
00246
00247 double X1p,Y1p,Z1p;
00248 double X1c,Y1c,Z1c,X2c;
00249 double X1cd,Y1cd,Z1cd;
00250
00251
00252 for (int32_t i=0; i<(int32_t)active.size(); i++) {
00253
00254
00255 X1p = X[active[i]];
00256 Y1p = Y[active[i]];
00257 Z1p = Z[active[i]];
00258
00259
00260 X1c = r00*X1p+r01*Y1p+r02*Z1p+tx;
00261 Y1c = r10*X1p+r11*Y1p+r12*Z1p+ty;
00262 Z1c = r20*X1p+r21*Y1p+r22*Z1p+tz;
00263
00264
00265 double weight = 1.0;
00266 if (param.reweighting)
00267 weight = 1.0/(fabs(p_observe[4*i+0]-param.calib.cu)/fabs(param.calib.cu) + 0.05);
00268
00269
00270 X2c = X1c-param.base;
00271
00272
00273 for (int32_t j=0; j<6; j++) {
00274
00275
00276 switch (j) {
00277 case 0: X1cd = 0;
00278 Y1cd = rdrx10*X1p+rdrx11*Y1p+rdrx12*Z1p;
00279 Z1cd = rdrx20*X1p+rdrx21*Y1p+rdrx22*Z1p;
00280 break;
00281 case 1: X1cd = rdry00*X1p+rdry01*Y1p+rdry02*Z1p;
00282 Y1cd = rdry10*X1p+rdry11*Y1p+rdry12*Z1p;
00283 Z1cd = rdry20*X1p+rdry21*Y1p+rdry22*Z1p;
00284 break;
00285 case 2: X1cd = rdrz00*X1p+rdrz01*Y1p;
00286 Y1cd = rdrz10*X1p+rdrz11*Y1p;
00287 Z1cd = rdrz20*X1p+rdrz21*Y1p;
00288 break;
00289 case 3: X1cd = 1; Y1cd = 0; Z1cd = 0; break;
00290 case 4: X1cd = 0; Y1cd = 1; Z1cd = 0; break;
00291 case 5: X1cd = 0; Y1cd = 0; Z1cd = 1; break;
00292 }
00293
00294
00295 J[(4*i+0)*6+j] = weight*param.calib.f*(X1cd*Z1c-X1c*Z1cd)/(Z1c*Z1c);
00296 J[(4*i+1)*6+j] = weight*param.calib.f*(Y1cd*Z1c-Y1c*Z1cd)/(Z1c*Z1c);
00297 J[(4*i+2)*6+j] = weight*param.calib.f*(X1cd*Z1c-X2c*Z1cd)/(Z1c*Z1c);
00298 J[(4*i+3)*6+j] = weight*param.calib.f*(Y1cd*Z1c-Y1c*Z1cd)/(Z1c*Z1c);
00299 }
00300
00301
00302 p_predict[4*i+0] = param.calib.f*X1c/Z1c+param.calib.cu;
00303 p_predict[4*i+1] = param.calib.f*Y1c/Z1c+param.calib.cv;
00304 p_predict[4*i+2] = param.calib.f*X2c/Z1c+param.calib.cu;
00305 p_predict[4*i+3] = param.calib.f*Y1c/Z1c+param.calib.cv;
00306
00307
00308 p_residual[4*i+0] = weight*(p_observe[4*i+0]-p_predict[4*i+0]);
00309 p_residual[4*i+1] = weight*(p_observe[4*i+1]-p_predict[4*i+1]);
00310 p_residual[4*i+2] = weight*(p_observe[4*i+2]-p_predict[4*i+2]);
00311 p_residual[4*i+3] = weight*(p_observe[4*i+3]-p_predict[4*i+3]);
00312 }
00313 }
00314