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