Added optional image center to Cal3Bundler, used only as a convenience constant so one does not need to transform the image coordinates.
parent
b51a8380c4
commit
8604bc7328
|
@ -29,18 +29,15 @@ Cal3Bundler::Cal3Bundler() :
|
|||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Cal3Bundler::Cal3Bundler(const Vector &v) :
|
||||
f_(v(0)), k1_(v(1)), k2_(v(2)) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Cal3Bundler::Cal3Bundler(const double f, const double k1, const double k2) :
|
||||
f_(f), k1_(k1), k2_(k2) {
|
||||
Cal3Bundler::Cal3Bundler(double f, double k1, double k2, double u0, double v0) :
|
||||
f_(f), k1_(k1), k2_(k2), u0_(u0), v0_(v0) {
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix Cal3Bundler::K() const {
|
||||
return Matrix_(3, 3, f_, 0.0, 0.0, 0.0, f_, 0.0, 0.0, 0.0, 1.0);
|
||||
Matrix3 K;
|
||||
K << f_, 0, u0_, 0, f_, v0_, 0, 0, 1;
|
||||
return K;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
@ -55,13 +52,14 @@ Vector Cal3Bundler::vector() const {
|
|||
|
||||
/* ************************************************************************* */
|
||||
void Cal3Bundler::print(const std::string& s) const {
|
||||
gtsam::print(vector(), s + ".K");
|
||||
gtsam::print(Vector_(5, f_, k1_, k2_, u0_, v0_), s + ".K");
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const {
|
||||
if (fabs(f_ - K.f_) > tol || fabs(k1_ - K.k1_) > tol
|
||||
|| fabs(k2_ - K.k2_) > tol)
|
||||
|| fabs(k2_ - K.k2_) > tol || fabs(u0_ - K.u0_) > tol
|
||||
|| fabs(v0_ - K.v0_) > tol)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -69,92 +67,59 @@ bool Cal3Bundler::equals(const Cal3Bundler& K, double tol) const {
|
|||
/* ************************************************************************* */
|
||||
Point2 Cal3Bundler::uncalibrate(const Point2& p, //
|
||||
boost::optional<Matrix&> Dcal, boost::optional<Matrix&> Dp) const {
|
||||
// r = x^2 + y^2;
|
||||
// g = (1 + k(1)*r + k(2)*r^2);
|
||||
// pi(:,i) = g * pn(:,i)
|
||||
// r = x^2 + y^2;
|
||||
// g = (1 + k(1)*r + k(2)*r^2);
|
||||
// pi(:,i) = g * pn(:,i)
|
||||
const double x = p.x(), y = p.y();
|
||||
const double r = x * x + y * y;
|
||||
const double g = 1. + (k1_ + k2_ * r) * r;
|
||||
const double u = g * x, v = g * y;
|
||||
const double f = f_;
|
||||
|
||||
// semantic meaningful version
|
||||
//if (H1) *H1 = D2d_calibration(p);
|
||||
//if (H2) *H2 = D2d_intrinsic(p);
|
||||
|
||||
// unrolled version, much faster
|
||||
if (Dcal || Dp) {
|
||||
// Derivatives make use of intermediate variables above
|
||||
if (Dcal) {
|
||||
double rx = r * x, ry = r * y;
|
||||
|
||||
if (Dcal) {
|
||||
Eigen::Matrix<double, 2, 3> D;
|
||||
D << u, f * rx, f * r * rx, v, f * ry, f * r * ry;
|
||||
*Dcal = D;
|
||||
}
|
||||
|
||||
if (Dp) {
|
||||
const double dg_dx = 2. * k1_ * x + 4. * k2_ * rx;
|
||||
const double dg_dy = 2. * k1_ * y + 4. * k2_ * ry;
|
||||
Eigen::Matrix<double, 2, 2> D;
|
||||
D << g + x * dg_dx, x * dg_dy, y * dg_dx, g + y * dg_dy;
|
||||
*Dp = f * D;
|
||||
}
|
||||
Eigen::Matrix<double, 2, 3> D;
|
||||
D << u, f_ * rx, f_ * r * rx, v, f_ * ry, f_ * r * ry;
|
||||
*Dcal = D;
|
||||
}
|
||||
|
||||
return Point2(f * u, f * v);
|
||||
if (Dp) {
|
||||
const double a = 2. * (k1_ + 2. * k2_ * r);
|
||||
const double axx = a * x * x, axy = a * x * y, ayy = a * y * y;
|
||||
Eigen::Matrix<double, 2, 2> D;
|
||||
D << g + axx, axy, axy, g + ayy;
|
||||
*Dp = f_ * D;
|
||||
}
|
||||
|
||||
return Point2(u0_ + f_ * u, v0_ + f_ * v);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix Cal3Bundler::D2d_intrinsic(const Point2& p) const {
|
||||
const double x = p.x(), y = p.y(), xx = x * x, yy = y * y;
|
||||
const double r = xx + yy;
|
||||
const double dr_dx = 2 * x;
|
||||
const double dr_dy = 2 * y;
|
||||
const double g = 1 + (k1_ + k2_ * r) * r;
|
||||
const double dg_dx = k1_ * dr_dx + k2_ * 2 * r * dr_dx;
|
||||
const double dg_dy = k1_ * dr_dy + k2_ * 2 * r * dr_dy;
|
||||
|
||||
Matrix DK = Matrix_(2, 2, f_, 0.0, 0.0, f_);
|
||||
Matrix DR = Matrix_(2, 2, g + x * dg_dx, x * dg_dy, y * dg_dx, g + y * dg_dy);
|
||||
return DK * DR;
|
||||
Matrix Dp;
|
||||
uncalibrate(p, boost::none, Dp);
|
||||
return Dp;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix Cal3Bundler::D2d_calibration(const Point2& p) const {
|
||||
|
||||
const double x = p.x(), y = p.y(), xx = x * x, yy = y * y;
|
||||
const double r = xx + yy;
|
||||
const double r2 = r * r;
|
||||
const double f = f_;
|
||||
const double g = 1 + (k1_ + k2_ * r) * r;
|
||||
|
||||
return Matrix_(2, 3, g * x, f * x * r, f * x * r2, g * y, f * y * r,
|
||||
f * y * r2);
|
||||
Matrix Dcal;
|
||||
uncalibrate(p, Dcal, boost::none);
|
||||
return Dcal;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Matrix Cal3Bundler::D2d_intrinsic_calibration(const Point2& p) const {
|
||||
|
||||
const double x = p.x(), y = p.y(), xx = x * x, yy = y * y;
|
||||
const double r = xx + yy;
|
||||
const double r2 = r * r;
|
||||
const double dr_dx = 2 * x;
|
||||
const double dr_dy = 2 * y;
|
||||
const double g = 1 + (k1_ + k2_ * r) * r;
|
||||
const double f = f_;
|
||||
const double dg_dx = k1_ * dr_dx + k2_ * 2 * r * dr_dx;
|
||||
const double dg_dy = k1_ * dr_dy + k2_ * 2 * r * dr_dy;
|
||||
|
||||
Matrix H = Matrix_(2, 5, f * (g + x * dg_dx), f * (x * dg_dy), g * x,
|
||||
f * x * r, f * x * r2, f * (y * dg_dx), f * (g + y * dg_dy), g * y,
|
||||
f * y * r, f * y * r2);
|
||||
|
||||
Matrix Dcal, Dp;
|
||||
uncalibrate(p, Dcal, Dp);
|
||||
Matrix H(2, 5);
|
||||
H << Dp, Dcal;
|
||||
return H;
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Cal3Bundler Cal3Bundler::retract(const Vector& d) const {
|
||||
return Cal3Bundler(vector() + d);
|
||||
return Cal3Bundler(f_ + d(0), k1_ + d(1), k2_ + d(2), u0_, v0_);
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
|
|
@ -28,16 +28,17 @@ namespace gtsam {
|
|||
* @addtogroup geometry
|
||||
* \nosubgrouping
|
||||
*/
|
||||
class GTSAM_EXPORT Cal3Bundler : public DerivedValue<Cal3Bundler> {
|
||||
class GTSAM_EXPORT Cal3Bundler: public DerivedValue<Cal3Bundler> {
|
||||
|
||||
private:
|
||||
double f_; ///< focal length
|
||||
double k1_, k2_;///< radial distortion
|
||||
double k1_, k2_; ///< radial distortion
|
||||
double u0_, v0_; ///< image center, not a parameter to be optimized but a constant
|
||||
|
||||
public:
|
||||
|
||||
Matrix K() const;///< Standard 3*3 calibration matrix
|
||||
Vector k() const;///< Radial distortion parameters
|
||||
Matrix K() const; ///< Standard 3*3 calibration matrix
|
||||
Vector k() const; ///< Radial distortion parameters (4 of them, 2 0)
|
||||
|
||||
Vector vector() const;
|
||||
|
||||
|
@ -47,15 +48,15 @@ public:
|
|||
/// Default constructor
|
||||
Cal3Bundler();
|
||||
|
||||
/// Constructor
|
||||
Cal3Bundler(const double f, const double k1, const double k2);
|
||||
|
||||
/// @}
|
||||
/// @name Advanced Constructors
|
||||
/// @{
|
||||
|
||||
/// Construct from vector
|
||||
Cal3Bundler(const Vector &v);
|
||||
/**
|
||||
* Constructor
|
||||
* @param f focal length
|
||||
* @param k1 first radial distortion coefficient (quadratic)
|
||||
* @param k2 second radial distortion coefficient (quartic)
|
||||
* @param u0 optional image center (default 0), considered a constant
|
||||
* @param v0 optional image center (default 0), considered a constant
|
||||
*/
|
||||
Cal3Bundler(double f, double k1, double k2, double u0 = 0, double v0 = 0);
|
||||
|
||||
/// @}
|
||||
/// @name Testable
|
||||
|
@ -78,17 +79,16 @@ public:
|
|||
* @param Dp optional 2*2 Jacobian wrpt intrinsic coordinates
|
||||
* @return point in image coordinates
|
||||
*/
|
||||
Point2 uncalibrate(const Point2& p,
|
||||
boost::optional<Matrix&> Dcal = boost::none,
|
||||
boost::optional<Matrix&> Dp = boost::none) const;
|
||||
Point2 uncalibrate(const Point2& p, boost::optional<Matrix&> Dcal =
|
||||
boost::none, boost::optional<Matrix&> Dp = boost::none) const;
|
||||
|
||||
/// 2*2 Jacobian of uncalibrate with respect to intrinsic coordinates
|
||||
/// @deprecated might be removed in next release, use uncalibrate
|
||||
Matrix D2d_intrinsic(const Point2& p) const;
|
||||
|
||||
/// 2*3 Jacobian of uncalibrate wrpt CalBundler parameters
|
||||
/// @deprecated might be removed in next release, use uncalibrate
|
||||
Matrix D2d_calibration(const Point2& p) const;
|
||||
|
||||
/// 2*5 Jacobian of uncalibrate wrpt both intrinsic and calibration
|
||||
/// @deprecated might be removed in next release, use uncalibrate
|
||||
Matrix D2d_intrinsic_calibration(const Point2& p) const;
|
||||
|
||||
/// @}
|
||||
|
@ -102,10 +102,14 @@ public:
|
|||
Vector localCoordinates(const Cal3Bundler& T2) const;
|
||||
|
||||
/// dimensionality
|
||||
virtual size_t dim() const {return 3;}
|
||||
virtual size_t dim() const {
|
||||
return 3;
|
||||
}
|
||||
|
||||
/// dimensionality
|
||||
static size_t Dim() {return 3;}
|
||||
static size_t Dim() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
|
@ -116,17 +120,19 @@ private:
|
|||
/** Serialization function */
|
||||
friend class boost::serialization::access;
|
||||
template<class Archive>
|
||||
void serialize(Archive & ar, const unsigned int version)
|
||||
{
|
||||
ar & boost::serialization::make_nvp("Cal3Bundler",
|
||||
boost::serialization::base_object<Value>(*this));
|
||||
void serialize(Archive & ar, const unsigned int version) {
|
||||
ar
|
||||
& boost::serialization::make_nvp("Cal3Bundler",
|
||||
boost::serialization::base_object<Value>(*this));
|
||||
ar & BOOST_SERIALIZATION_NVP(f_);
|
||||
ar & BOOST_SERIALIZATION_NVP(k1_);
|
||||
ar & BOOST_SERIALIZATION_NVP(k2_);
|
||||
ar & BOOST_SERIALIZATION_NVP(u0_);
|
||||
ar & BOOST_SERIALIZATION_NVP(v0_);
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace gtsam
|
||||
} // namespace gtsam
|
||||
|
|
|
@ -25,7 +25,7 @@ using namespace gtsam;
|
|||
GTSAM_CONCEPT_TESTABLE_INST(Cal3Bundler)
|
||||
GTSAM_CONCEPT_MANIFOLD_INST(Cal3Bundler)
|
||||
|
||||
static Cal3Bundler K(500, 1e-3, 1e-3);
|
||||
static Cal3Bundler K(500, 1e-3, 1e-3, 1000, 2000);
|
||||
static Point2 p(2,3);
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
@ -34,11 +34,12 @@ TEST( Cal3Bundler, calibrate)
|
|||
Vector v = K.vector() ;
|
||||
double r = p.x()*p.x() + p.y()*p.y() ;
|
||||
double g = v[0]*(1+v[1]*r+v[2]*r*r) ;
|
||||
Point2 q_hat (g*p.x(), g*p.y()) ;
|
||||
Point2 q = K.uncalibrate(p);
|
||||
CHECK(assert_equal(q,q_hat));
|
||||
Point2 expected (1000+g*p.x(), 2000+g*p.y()) ;
|
||||
Point2 actual = K.uncalibrate(p);
|
||||
CHECK(assert_equal(actual,expected));
|
||||
}
|
||||
|
||||
/* ************************************************************************* */
|
||||
Point2 uncalibrate_(const Cal3Bundler& k, const Point2& pt) { return k.uncalibrate(pt); }
|
||||
|
||||
/* ************************************************************************* */
|
||||
|
@ -46,7 +47,7 @@ TEST( Cal3Bundler, Duncalibrate)
|
|||
{
|
||||
Matrix Dcal, Dp;
|
||||
Point2 actual = K.uncalibrate(p, Dcal, Dp);
|
||||
Point2 expected(1182, 1773);
|
||||
Point2 expected(2182, 3773);
|
||||
CHECK(assert_equal(expected,actual,1e-7));
|
||||
Matrix numerical1 = numericalDerivative21(uncalibrate_, K, p);
|
||||
Matrix numerical2 = numericalDerivative22(uncalibrate_, K, p);
|
||||
|
@ -68,7 +69,7 @@ TEST( Cal3Bundler, assert_equal)
|
|||
/* ************************************************************************* */
|
||||
TEST( Cal3Bundler, retract)
|
||||
{
|
||||
Cal3Bundler expected(510, 2e-3, 2e-3);
|
||||
Cal3Bundler expected(510, 2e-3, 2e-3, 1000, 2000);
|
||||
Vector d(3);
|
||||
d << 10, 1e-3, 1e-3;
|
||||
Cal3Bundler actual = K.retract(d);
|
||||
|
|
|
@ -52,7 +52,7 @@ int main()
|
|||
// Cal3DS2: 0.14201 musecs/call
|
||||
// After Cal3DS2 fix: 0.12231 musecs/call
|
||||
// Cal3Bundler: 0.12000 musecs/call
|
||||
// Cal3Bundler fix: 0.13864 musecs/call
|
||||
// Cal3Bundler fix: 0.14637 musecs/call
|
||||
{
|
||||
long timeLog = clock();
|
||||
for(int i = 0; i < n; i++)
|
||||
|
@ -64,12 +64,12 @@ int main()
|
|||
}
|
||||
|
||||
// Oct 12 2013, iMac 3.06GHz Core i3
|
||||
// Original: 3.87199 musecs/call
|
||||
// After collapse: 2.62684 musecs/call
|
||||
// Cal3DS2: 4.33297 musecs/call
|
||||
// After Cal3DS2 fix: 3.28565 musecs/call
|
||||
// Cal3Bundler: 2.65559 musecs/call
|
||||
// Cal3Bundler fix: 2.18481 musecs/call
|
||||
// Original: 3.8720 musecs/call
|
||||
// After collapse: 2.6269 musecs/call
|
||||
// Cal3DS2: 4.3330 musecs/call
|
||||
// After Cal3DS2 fix: 3.2857 musecs/call
|
||||
// Cal3Bundler: 2.6556 musecs/call
|
||||
// Cal3Bundler fix: 2.1613 musecs/call
|
||||
{
|
||||
Matrix Dpose, Dpoint;
|
||||
long timeLog = clock();
|
||||
|
@ -84,10 +84,10 @@ int main()
|
|||
// Oct 12 2013, iMac 3.06GHz Core i3
|
||||
// Original: 4.0119 musecs/call
|
||||
// After collapse: 2.5698 musecs/call
|
||||
// Cal3DS2: 4.83248 musecs/call
|
||||
// After Cal3DS2 fix: 3.44832 musecs/call
|
||||
// Cal3Bundler: 2.51124 musecs/call
|
||||
// Cal3Bundler fix: 2.17292 musecs/call
|
||||
// Cal3DS2: 4.8325 musecs/call
|
||||
// After Cal3DS2 fix: 3.4483 musecs/call
|
||||
// Cal3Bundler: 2.5112 musecs/call
|
||||
// Cal3Bundler fix: 2.0946 musecs/call
|
||||
{
|
||||
Matrix Dpose, Dpoint, Dcal;
|
||||
long timeLog = clock();
|
||||
|
|
Loading…
Reference in New Issue