00001
00028 #pragma once
00029
00030 #include <string>
00031 #include <sstream>
00032 #include <math.h>
00033 #include <Eigen/Dense>
00034
00035 #include "Node.h"
00036 #include "Factor.h"
00037 #include "Pose3d.h"
00038 #include "Point3dh.h"
00039
00040 namespace isam {
00041
00042 class StereoMeasurement {
00043 friend std::ostream& operator<<(std::ostream& out, const StereoMeasurement& t) {
00044 t.write(out);
00045 return out;
00046 }
00047
00048 public:
00049 double u;
00050 double v;
00051 double u2;
00052 bool valid;
00053
00054 StereoMeasurement(double u, double v, double u2)
00055 : u(u), v(v), u2(u2), valid(true) {
00056 }
00057 StereoMeasurement(double u, double v, double u2, bool valid)
00058 : u(u), v(v), u2(u2), valid(valid) {
00059 }
00060
00061 Eigen::Vector2d left_pixel() const {Eigen::Vector2d V(2); V << u, v; return V;}
00062
00063 Eigen::Vector2d right_pixel() const {Eigen::Vector2d V(2); V << u2, v; return V;}
00064
00065 double disparity() const {return u-u2;}
00066
00067 Eigen::Vector3d vector() const {
00068 Eigen::Vector3d tmp(u, v, u2);
00069 return tmp;
00070 }
00071
00072 void write(std::ostream &out) const {
00073 out << "(" << u << ", " << v << ", " << u2 << ")";
00074 }
00075 };
00076
00077 class StereoCamera {
00078 double _f;
00079 Eigen::Vector2d _pp;
00080 double _b;
00081
00082 public:
00083 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00084
00085 StereoCamera() : _f(1), _pp(Eigen::Vector2d(0.5,0.5)), _b(0.1) {}
00086 StereoCamera(double f, const Eigen::Vector2d& pp, double b) : _f(f), _pp(pp), _b(b) {}
00087
00088 inline double focalLength() const {return _f;}
00089
00090 inline Eigen::Vector2d principalPoint() const {return _pp;}
00091
00092 inline double baseline() const {return _b;}
00093
00094 StereoMeasurement project(const Pose3d& pose, const Point3dh& Xw) const {
00095 Point3dh X = pose.transform_to(Xw);
00096
00097 double x = X.y();
00098 double y = X.z();
00099 double z = X.x();
00100 double w = X.w();
00101
00102 double fz = _f / z;
00103 double u = x * fz + _pp(0);
00104 double v = y * fz + _pp(1);
00105
00106 double u2 = (x - w*_b) * fz + _pp(0);
00107 bool valid = ((w==0&&z>0) || (z/w) > 0.);
00108
00109
00110
00111
00112
00113 return StereoMeasurement(u, v, u2, valid);
00114 }
00115
00116
00117 Point3dh backproject(const Pose3d& pose, const StereoMeasurement& measure) const {
00118 double lx = (measure.u-_pp(0))*_b;
00119 double ly = (measure.v-_pp(1))*_b;
00120 double lz = _f*_b;
00121 double lw = measure.u - measure.u2;
00122 if (lw<0.) {
00123 std::cout << "Warning: StereoCamera.backproject called with negative disparity\n";
00124 }
00125 Point3dh X(lz, lx, ly, lw);
00126
00127 return pose.transform_from(X);
00128 }
00129
00130 };
00131
00136 class Stereo_Factor : public FactorT<StereoMeasurement> {
00137 Pose3d_Node* _pose;
00138 Point3d_Node* _point;
00139 Point3dh_Node* _point_h;
00140 StereoCamera* _camera;
00141 bool _relative;
00142 Pose3d_Node* _base;
00143
00144 public:
00145
00146
00147 Stereo_Factor(Pose3d_Node* pose, Point3dh_Node* point, StereoCamera* camera,
00148 const StereoMeasurement& measure, const Noise& noise, bool relative = false)
00149 : FactorT<StereoMeasurement>("Stereo_Factor", 3, noise, measure),
00150 _pose(pose), _point(NULL), _point_h(point), _camera(camera), _relative(relative), _base(NULL) {
00151
00152
00153 _nodes.resize(2);
00154 _nodes[0] = pose;
00155 _nodes[1] = point;
00156
00157 if (_relative) {
00158 if (!point->factors().empty()) {
00159 _nodes.resize(3);
00160 _nodes[2] = point->factors().front()->nodes()[0];
00161
00162 _base = dynamic_cast<Pose3d_Node*>(_nodes[2]);
00163 } else {
00164 _base = _pose;
00165 }
00166 point->set_base(_base);
00167 }
00168 }
00169
00170
00171
00172 Stereo_Factor(Pose3d_Node* pose, Point3d_Node* point, StereoCamera* camera,
00173 const StereoMeasurement& measure, const Noise& noise, bool relative = false)
00174 : FactorT<StereoMeasurement>("Stereo_Factor", 3, noise, measure),
00175 _pose(pose), _point(point), _point_h(NULL), _camera(camera), _relative(relative), _base(NULL) {
00176 _nodes.resize(2);
00177 _nodes[0] = pose;
00178 _nodes[1] = point;
00179
00180 if (_relative) {
00181 if (!point->factors().empty()) {
00182 _nodes.resize(3);
00183 _nodes[2] = point->factors().front()->nodes()[0];
00184
00185 _base = dynamic_cast<Pose3d_Node*>(_nodes[2]);
00186 } else {
00187 _base = _pose;
00188 }
00189 point->set_base(_base);
00190 }
00191 }
00192
00193 void initialize() {
00194 require(_pose->initialized(), "Stereo_Factor requires pose to be initialized");
00195 bool initialized = (_point_h!=NULL) ? _point_h->initialized() : _point->initialized();
00196 if (!initialized) {
00197 Point3dh predict;
00198 if (_relative) {
00199 predict = _camera->backproject(Pose3d(), _measure);
00200 } else {
00201 predict = _camera->backproject(_pose->value(), _measure);
00202 }
00203
00204 predict = Point3dh(predict.vector()).normalize();
00205 if (_point_h!=NULL) {
00206 _point_h->init(predict);
00207 } else {
00208 _point->init(predict.to_point3d());
00209 }
00210 }
00211 }
00212
00213 Eigen::VectorXd basic_error(Selector s = ESTIMATE) const {
00214 Point3dh point = (_point_h!=NULL) ? _point_h->value(s) : _point->value(s);
00215 Pose3d pose = _pose->value(s);
00216 if (_base) {
00217
00218 pose = pose.ominus(_base->value(s));
00219 }
00220 StereoMeasurement predicted = _camera->project(pose, point);
00221 if (_point_h!=NULL || predicted.valid == true) {
00222 return (predicted.vector() - _measure.vector());
00223 } else {
00224
00225 std::cout << "Warning - StereoFactor.basic_error: " << this
00226 << " #: " << _nodes[1]->factors().size() << " " << _nodes[0]->factors().size()
00227 << " \npoint: " << point << " ptr: " << _point
00228 << " pose: " << pose << " ptr: " << _pose
00229 << " \npredicted: " << predicted.vector().transpose()
00230 << " measure: " << _measure.vector().transpose() << std::endl;
00231 return Eigen::Vector3d::Zero();
00232 }
00233 }
00234
00235 };
00236
00237 }