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