1 // g2o - General Graph Optimization 2 // Copyright (C) 2011 Kurt Konolige 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright notice, 10 // this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above copyright 12 // notice, this list of conditions and the following disclaimer in the 13 // documentation and/or other materials provided with the distribution. 14 // 15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 16 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 17 // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 18 // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 21 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 23 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 24 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27 #ifndef G2O_SBA_TYPES 28 #define G2O_SBA_TYPES 29 30 #include "g2o/core/base_vertex.h" 31 #include "g2o/core/base_binary_edge.h" 32 #include "g2o/core/base_multi_edge.h" 33 #include "sbacam.h" 34 #include <Eigen/Geometry> 35 #include <iostream> 36 37 #include "g2o_types_sba_api.h" 38 39 namespace g2o { 40 41 /** 42 * \brief Vertex encoding the intrinsics of the camera fx, fy, cx, xy, baseline; 43 */ 44 class G2O_TYPES_SBA_API VertexIntrinsics : public BaseVertex<4, Eigen::Matrix<number_t, 5, 1, Eigen::ColMajor> > 45 { 46 public: 47 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 48 VertexIntrinsics(); 49 virtual bool read(std::istream& is); 50 virtual bool write(std::ostream& os) const; 51 setToOriginImpl()52 virtual void setToOriginImpl() { 53 _estimate << cst(1.), cst(1.), cst(0.5), cst(0.5), cst(0.1); 54 } 55 oplusImpl(const number_t * update)56 virtual void oplusImpl(const number_t* update) 57 { 58 _estimate.head<4>() += Vector4(update); 59 } 60 }; 61 62 /** 63 * \brief SBACam Vertex, (x,y,z,qw,qx,qy,qz) 64 * the parameterization for the increments constructed is a 6d vector 65 * (x,y,z,qx,qy,qz) (note that we leave out the w part of the quaternion. 66 * qw is assumed to be positive, otherwise there is an ambiguity in qx,qy,qz as a rotation 67 */ 68 class G2O_TYPES_SBA_API VertexCam : public BaseVertex<6, SBACam> 69 { 70 public: 71 EIGEN_MAKE_ALIGNED_OPERATOR_NEW; 72 VertexCam(); 73 74 virtual bool read(std::istream& is); 75 virtual bool write(std::ostream& os) const; 76 setToOriginImpl()77 virtual void setToOriginImpl() { 78 _estimate = SBACam(); 79 } 80 setEstimate(const SBACam & cam)81 virtual void setEstimate(const SBACam& cam){ 82 BaseVertex<6, SBACam>::setEstimate(cam); 83 _estimate.setTransform(); 84 _estimate.setProjection(); 85 _estimate.setDr(); 86 } 87 oplusImpl(const number_t * update)88 virtual void oplusImpl(const number_t* update) 89 { 90 Eigen::Map<const Vector6> v(update); 91 _estimate.update(v); 92 _estimate.setTransform(); 93 _estimate.setProjection(); 94 _estimate.setDr(); 95 } 96 97 setEstimateDataImpl(const number_t * est)98 virtual bool setEstimateDataImpl(const number_t* est){ 99 Eigen::Map <const Vector7> v(est); 100 _estimate.fromVector(v); 101 return true; 102 } 103 getEstimateData(number_t * est)104 virtual bool getEstimateData(number_t* est) const{ 105 Eigen::Map <Vector7> v(est); 106 v = estimate().toVector(); 107 return true; 108 } 109 estimateDimension()110 virtual int estimateDimension() const { 111 return 7; 112 } 113 setMinimalEstimateDataImpl(const number_t * est)114 virtual bool setMinimalEstimateDataImpl(const number_t* est){ 115 Eigen::Map<const Vector6> v(est); 116 _estimate.fromMinimalVector(v); 117 return true; 118 } 119 getMinimalEstimateData(number_t * est)120 virtual bool getMinimalEstimateData(number_t* est) const{ 121 Eigen::Map<Vector6> v(est); 122 v = _estimate.toMinimalVector(); 123 return true; 124 } 125 minimalEstimateDimension()126 virtual int minimalEstimateDimension() const { 127 return 6; 128 } 129 }; 130 131 /** 132 * \brief Point vertex, XYZ 133 */ 134 class G2O_TYPES_SBA_API VertexSBAPointXYZ : public BaseVertex<3, Vector3> 135 { 136 public: 137 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 138 VertexSBAPointXYZ(); 139 virtual bool read(std::istream& is); 140 virtual bool write(std::ostream& os) const; 141 setToOriginImpl()142 virtual void setToOriginImpl() { 143 _estimate.fill(0); 144 } 145 oplusImpl(const number_t * update)146 virtual void oplusImpl(const number_t* update) 147 { 148 Eigen::Map<const Vector3> v(update); 149 _estimate += v; 150 } 151 }; 152 153 154 // monocular projection 155 // first two args are the measurement type, second two the connection classes 156 class G2O_TYPES_SBA_API EdgeProjectP2MC : public BaseBinaryEdge<2, Vector2, VertexSBAPointXYZ, VertexCam> 157 { 158 public: 159 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 160 EdgeProjectP2MC(); 161 virtual bool read(std::istream& is); 162 virtual bool write(std::ostream& os) const; 163 164 // return the error estimate as a 2-vector computeError()165 void computeError() 166 { 167 // from <Point> to <Cam> 168 const VertexSBAPointXYZ *point = static_cast<const VertexSBAPointXYZ*>(_vertices[0]); 169 const VertexCam *cam = static_cast<const VertexCam*>(_vertices[1]); 170 171 // calculate the projection 172 const Vector3 &pt = point->estimate(); 173 Vector4 ppt(pt(0),pt(1),pt(2),1); 174 Vector3 p = cam->estimate().w2i * ppt; 175 Vector2 perr; 176 perr = p.head<2>()/p(2); 177 // std::cout << std::endl << "CAM " << cam->estimate() << std::endl; 178 // std::cout << "POINT " << pt.transpose() << std::endl; 179 // std::cout << "PROJ " << p.transpose() << std::endl; 180 // std::cout << "CPROJ " << perr.transpose() << std::endl; 181 // std::cout << "MEAS " << _measurement.transpose() << std::endl; 182 183 // error, which is backwards from the normal observed - calculated 184 // _measurement is the measured projection 185 _error = perr - _measurement; 186 // std::cerr << _error.x() << " " << _error.y() << " " << chi2() << std::endl; 187 } 188 189 // jacobian 190 virtual void linearizeOplus(); 191 }; 192 193 // stereo projection 194 // first two args are the measurement type, second two the connection classes 195 class G2O_TYPES_SBA_API EdgeProjectP2SC : public BaseBinaryEdge<3, Vector3, VertexSBAPointXYZ, VertexCam> 196 { 197 public: 198 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 199 EdgeProjectP2SC(); 200 virtual bool read(std::istream& is); 201 virtual bool write(std::ostream& os) const; 202 203 // return the error estimate as a 2-vector computeError()204 void computeError() 205 { 206 // from <Point> to <Cam> 207 const VertexSBAPointXYZ *point = static_cast<const VertexSBAPointXYZ*>(_vertices[0]); 208 VertexCam *cam = static_cast<VertexCam*>(_vertices[1]); 209 210 // calculate the projection 211 Vector3 kp; 212 Vector4 pt; 213 pt.head<3>() = point->estimate(); 214 pt(3) = 1; 215 const SBACam& nd = cam->estimate(); 216 // these should be already ok 217 /* nd.setTransform(); */ 218 /* nd.setProjection(); */ 219 /* nd.setDr(); */ 220 221 Vector3 p1 = nd.w2i * pt; 222 Vector3 p2 = nd.w2n * pt; 223 Vector3 pb(nd.baseline,0,0); 224 225 number_t invp1 = cst(1.0)/p1(2); 226 kp.head<2>() = p1.head<2>()*invp1; 227 228 // right camera px 229 p2 = nd.Kcam*(p2-pb); 230 kp(2) = p2(0)/p2(2); 231 232 // std::cout << std::endl << "CAM " << cam->estimate() << std::endl; 233 // std::cout << "POINT " << pt.transpose() << std::endl; 234 // std::cout << "PROJ " << p1.transpose() << std::endl; 235 // std::cout << "PROJ " << p2.transpose() << std::endl; 236 // std::cout << "CPROJ " << kp.transpose() << std::endl; 237 // std::cout << "MEAS " << _measurement.transpose() << std::endl; 238 239 // error, which is backwards from the normal observed - calculated 240 // _measurement is the measured projection 241 _error = kp - _measurement; 242 } 243 244 // jacobian 245 virtual void linearizeOplus(); 246 247 }; 248 249 /** 250 * \brief 3D edge between two SBAcam 251 */ 252 class G2O_TYPES_SBA_API EdgeSBACam : public BaseBinaryEdge<6, SE3Quat, VertexCam, VertexCam> 253 { 254 public: 255 EIGEN_MAKE_ALIGNED_OPERATOR_NEW; 256 EdgeSBACam(); 257 virtual bool read(std::istream& is); 258 virtual bool write(std::ostream& os) const; computeError()259 void computeError() 260 { 261 const VertexCam* v1 = dynamic_cast<const VertexCam*>(_vertices[0]); 262 const VertexCam* v2 = dynamic_cast<const VertexCam*>(_vertices[1]); 263 SE3Quat delta = _inverseMeasurement * (v1->estimate().inverse()*v2->estimate()); 264 _error[0]=delta.translation().x(); 265 _error[1]=delta.translation().y(); 266 _error[2]=delta.translation().z(); 267 _error[3]=delta.rotation().x(); 268 _error[4]=delta.rotation().y(); 269 _error[5]=delta.rotation().z(); 270 } 271 setMeasurement(const SE3Quat & meas)272 virtual void setMeasurement(const SE3Quat& meas){ 273 _measurement=meas; 274 _inverseMeasurement=meas.inverse(); 275 } 276 initialEstimatePossible(const OptimizableGraph::VertexSet &,OptimizableGraph::Vertex *)277 virtual number_t initialEstimatePossible(const OptimizableGraph::VertexSet& , OptimizableGraph::Vertex* ) { return cst(1.);} 278 virtual void initialEstimate(const OptimizableGraph::VertexSet& from, OptimizableGraph::Vertex* to); 279 setMeasurementData(const number_t * d)280 virtual bool setMeasurementData(const number_t* d){ 281 Eigen::Map<const Vector7> v(d); 282 _measurement.fromVector(v); 283 _inverseMeasurement = _measurement.inverse(); 284 return true; 285 } 286 getMeasurementData(number_t * d)287 virtual bool getMeasurementData(number_t* d) const{ 288 Eigen::Map<Vector7> v(d); 289 v = _measurement.toVector(); 290 return true; 291 } 292 measurementDimension()293 virtual int measurementDimension() const {return 7;} 294 295 virtual bool setMeasurementFromState(); 296 297 protected: 298 SE3Quat _inverseMeasurement; 299 }; 300 301 302 /** 303 * \brief edge between two SBAcam that specifies the distance between them 304 */ 305 class G2O_TYPES_SBA_API EdgeSBAScale : public BaseBinaryEdge<1, number_t, VertexCam, VertexCam> 306 { 307 public: 308 EIGEN_MAKE_ALIGNED_OPERATOR_NEW 309 EdgeSBAScale(); 310 virtual bool read(std::istream& is); 311 virtual bool write(std::ostream& os) const; computeError()312 void computeError() 313 { 314 const VertexCam* v1 = dynamic_cast<const VertexCam*>(_vertices[0]); 315 const VertexCam* v2 = dynamic_cast<const VertexCam*>(_vertices[1]); 316 Vector3 dt=v2->estimate().translation()-v1->estimate().translation(); 317 _error[0] = _measurement - dt.norm(); 318 } setMeasurement(const number_t & m)319 virtual void setMeasurement(const number_t& m){ 320 _measurement = m; 321 } initialEstimatePossible(const OptimizableGraph::VertexSet &,OptimizableGraph::Vertex *)322 virtual number_t initialEstimatePossible(const OptimizableGraph::VertexSet& , OptimizableGraph::Vertex* ) { return cst(1.);} 323 virtual void initialEstimate(const OptimizableGraph::VertexSet& from_, OptimizableGraph::Vertex* to_); 324 }; 325 326 327 328 } // end namespace 329 330 #endif // SBA_TYPES 331