ObjectPose.cpp
Go to the documentation of this file.
00001 // ****************************************************************************
00002 // This file is part of the Integrating Vision Toolkit (IVT).
00003 //
00004 // The IVT is maintained by the Karlsruhe Institute of Technology (KIT)
00005 // (www.kit.edu) in cooperation with the company Keyetech (www.keyetech.de).
00006 //
00007 // Copyright (C) 2014 Karlsruhe Institute of Technology (KIT).
00008 // All rights reserved.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are met:
00012 //
00013 // 1. Redistributions of source code must retain the above copyright
00014 //    notice, this list of conditions and the following disclaimer.
00015 //
00016 // 2. Redistributions in binary form must reproduce the above copyright
00017 //    notice, this list of conditions and the following disclaimer in the
00018 //    documentation and/or other materials provided with the distribution.
00019 //
00020 // 3. Neither the name of the KIT nor the names of its contributors may be
00021 //    used to endorse or promote products derived from this software
00022 //    without specific prior written permission.
00023 //
00024 // THIS SOFTWARE IS PROVIDED BY THE KIT AND CONTRIBUTORS “AS IS” AND ANY
00025 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00026 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027 // DISCLAIMED. IN NO EVENT SHALL THE KIT OR CONTRIBUTORS BE LIABLE FOR ANY
00028 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00029 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00031 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00032 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00033 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034 // ****************************************************************************
00035 // ****************************************************************************
00036 // Filename:  ObjectPose.h
00037 // Author:    Moritz Ritter
00038 // Date:      08.04.2008
00039 // ****************************************************************************
00040 
00041 // ****************************************************************************
00042 // Implementation of the paper:
00043 // "Fast and Globally Convergent Pose Estimation from Video Images"
00044 // IEEE Transactions on Pattern Analysis and Machine Intelligence,
00045 // vol. 22, no.6, June 2000
00046 //
00047 // Solves the 2D to 3D mapping problem for 3 or more non-colinear
00048 // points (also for coplanar points).
00049 // ****************************************************************************
00050 
00051 
00052 // ****************************************************************************
00053 // Includes
00054 // ****************************************************************************
00055 
00056 #include <new> // for explicitly using correct new/delete operators on VC DSPs
00057 
00058 #include "ObjectPose.h"
00059 
00060 #include "Math/Math2d.h"
00061 #include "Math/Math3d.h"
00062 #include "Math/DoubleMatrix.h"
00063 #include "Math/LinearAlgebra.h"
00064 #include "Calibration/Calibration.h"
00065 
00066 #include <math.h>
00067 #include <stdio.h>
00068 
00069 
00070 // ****************************************************************************
00071 // Defines
00072 // ****************************************************************************
00073 
00074 #define TOL 1e-5
00075 #define EPSILON 1e-8
00076 
00077 
00078 
00079 
00080 // ****************************************************************************
00081 // Constructor / Destructor
00082 // ****************************************************************************
00083 
00084 CObjectPose::CObjectPose(const Vec3d *pObjectPoints, int nPoints)
00085 {
00086         int i;
00087 
00088         m_nPoints = nPoints;
00089 
00090         // normalized object points 3xn matrix
00091         m_pP = new Vec3d[m_nPoints]; 
00092         
00093         m_tPbar = pObjectPoints[0];
00094         for (i = 1; i < m_nPoints; i++)
00095                 Math3d::AddToVec(m_tPbar, pObjectPoints[i]);
00096 
00097         Math3d::MulVecScalar(m_tPbar, 1.0f / m_nPoints, m_tPbar);
00098 
00099         for (i = 0; i < m_nPoints; i++)
00100                 Math3d::SubtractVecVec(pObjectPoints[i], m_tPbar, m_pP[i]);
00101 
00102         // homogeneous normalized image points 3xn matrix
00103         m_pQ = new Vec3d[m_nPoints];
00104 
00105         // 3x3xn matrix
00106         m_pF = new Mat3d[m_nPoints];
00107 }
00108 
00109 CObjectPose::~CObjectPose()
00110 {
00111         delete [] m_pP;
00112         delete [] m_pQ;
00113         delete [] m_pF;
00114 }
00115 
00116 
00117 // ****************************************************************************
00118 // Methods
00119 // ****************************************************************************
00120 
00121 bool CObjectPose::EstimatePose(const Vec2d *pImagePoints,
00122         Mat3d &rotationMatrix, Vec3d &translationVector,
00123         const CCalibration *pCalibration, int nMaxIterations)
00124 {
00125         if (m_nPoints < 3)
00126         {
00127                 printf("error: too few points for object pose estimation.\n");
00128                 return false;
00129         }
00130 
00131         int i;
00132 
00133         // normalize image points
00134         const Vec2d &focalLength = pCalibration->GetCameraParameters().focalLength;
00135         const Vec2d &principalPoint = pCalibration->GetCameraParameters().principalPoint;
00136 
00137         for (i = 0; i < m_nPoints; i++)
00138         {
00139                 m_pQ[i].x = (pImagePoints[i].x - principalPoint.x) / focalLength.x;
00140                 m_pQ[i].y = (pImagePoints[i].y - principalPoint.y) / focalLength.y;
00141                 m_pQ[i].z = 1.0;
00142         }
00143 
00144         // compute projection matrices
00145         for (i = 0; i < m_nPoints; i++)
00146         {
00147                 const float scalar = 1.0f / Math3d::SquaredLength(m_pQ[i]);
00148                 Math3d::MulVecTransposedVec(m_pQ[i], m_pQ[i], m_pF[i]);
00149                 Math3d::MulMatScalar(m_pF[i], scalar, m_pF[i]);
00150         }
00151 
00152         // compute the matrix factor required for computing t ( inv( eye(3) - sum(F,3) / n ) / n )
00153         Mat3d sum;
00154         Mat3d temp;
00155         // sum(F, 3)
00156         sum = m_pF[0];
00157         for (i = 1; i < m_nPoints; i++)
00158                 Math3d::AddToMat(sum, m_pF[i]);
00159         // sum / n
00160         Math3d::MulMatScalar(sum, 1.0f / m_nPoints, sum);
00161         // eye(3) - sum
00162         Math3d::SubtractMatMat(Math3d::unit_mat, sum, temp);
00163         // inv(temp)
00164         Math3d::Invert(temp, temp);
00165         // m_tFactor = temp / n
00166         Math3d::MulMatScalar(temp, 1.0f / m_nPoints, m_tFactor);
00167 
00168         float old_error, new_error;
00169         int it = 0;
00170 
00171         AbsKernel(rotationMatrix, translationVector, old_error);
00172         it++;
00173         AbsKernel(rotationMatrix, translationVector, new_error);
00174         it++;
00175 
00176         while (fabsf((old_error - new_error) / old_error) > TOL && new_error > EPSILON && it < nMaxIterations)
00177         {
00178                 old_error = new_error;
00179                 AbsKernel(rotationMatrix, translationVector, new_error);
00180                 it++;
00181         }
00182 
00183         // get back to original reference frame
00184         Vec3d vec;
00185         Math3d::MulMatVec(rotationMatrix, m_tPbar, vec);
00186         Math3d::SubtractVecVec(translationVector, vec, translationVector);
00187 
00188         // take into account extrinsic calibration
00189         const Mat3d &Rc = pCalibration->m_rotation_inverse;
00190         const Vec3d &tc = pCalibration->m_translation_inverse;
00191         Math3d::MulMatMat(Rc, rotationMatrix, rotationMatrix);
00192         Math3d::MulMatVec(Rc, translationVector, tc, translationVector);
00193 
00194         return true;
00195 }
00196 
00197 void CObjectPose::AbsKernel(Mat3d &R, Vec3d &t, float &error)
00198 {
00199         int i;
00200 
00201         // compute Q
00202         for (i = 0; i < m_nPoints; i++)
00203                 Math3d::MulMatVec(m_pF[i], m_pQ[i], m_pQ[i]);
00204         
00205         // compute Q relative to qbar
00206         Vec3d qbar;
00207         qbar = m_pQ[0];
00208         for (i = 1; i < m_nPoints; i++)
00209                 Math3d::AddToVec(qbar, m_pQ[i]);
00210         Math3d::MulVecScalar(qbar, 1.0f / m_nPoints, qbar);
00211         for (i = 0; i < m_nPoints; i++)
00212                 Math3d::SubtractVecVec(m_pQ[i], qbar, m_pQ[i]);
00213 
00214         // compute M matrix ( M = M + P(:, i) * Q(:, i)' )
00215         CDoubleMatrix fM(3, 3);
00216         Mat3d temp;
00217         for (i = 0; i < 9; i++)
00218                 fM.data[i] = 0; 
00219         for (i = 0; i < m_nPoints; i++)
00220         {
00221                 Math3d::MulVecTransposedVec(m_pP[i], m_pQ[i], temp);
00222                 fM.data[0] = fM.data[0] + temp.r1; fM.data[1] = fM.data[1] + temp.r2; fM.data[2] = fM.data[2] + temp.r3;
00223                 fM.data[3] = fM.data[3] + temp.r4; fM.data[4] = fM.data[4] + temp.r5; fM.data[5] = fM.data[5] + temp.r6;
00224                 fM.data[6] = fM.data[6] + temp.r7; fM.data[7] = fM.data[7] + temp.r8; fM.data[8] = fM.data[8] + temp.r9;
00225         }
00226         
00227         // calculate SVD of M
00228         CDoubleMatrix fU(3, 3);
00229         CDoubleMatrix fS(3, 3);
00230         CDoubleMatrix fV(3, 3);
00231         LinearAlgebra::SVD(&fM, &fS, &fU, &fV);
00232         
00233         // compute transposed U
00234         Mat3d transU;
00235         LinearAlgebra::Transpose(&fU, &fU);
00236         transU.r1 = float(fU.data[0]); transU.r2 = float(fU.data[1]); transU.r3 = float(fU.data[2]);
00237         transU.r4 = float(fU.data[3]); transU.r5 = float(fU.data[4]); transU.r6 = float(fU.data[5]);
00238         transU.r7 = float(fU.data[6]); transU.r8 = float(fU.data[7]); transU.r9 = float(fU.data[8]);
00239         
00240         // R = V * U'
00241         temp.r1 = float(fV.data[0]); temp.r2 = float(fV.data[1]); temp.r3 = float(fV.data[2]);
00242         temp.r4 = float(fV.data[3]); temp.r5 = float(fV.data[4]); temp.r6 = float(fV.data[5]);
00243         temp.r7 = float(fV.data[6]); temp.r8 = float(fV.data[7]); temp.r9 = float(fV.data[8]);
00244         Math3d::MulMatMat(temp, transU, R);
00245 
00246         if (Math3d::Det(R) > 0)
00247         {
00248                 // no need to change R
00249                 // estimate current translation
00250                 t = tEstimate(R);
00251 
00252                 if (t.z < 0) // we need to invert t (object should be in front of the camera)
00253                 {
00254                         // R = -[V(:, 1:2) -V(:, 3)] * U'
00255                         temp.r1 = float(-fV.data[0]); temp.r2 = float(-fV.data[1]); temp.r3 = float(fV.data[2]);
00256                         temp.r4 = float(-fV.data[3]); temp.r5 = float(-fV.data[4]); temp.r6 = float(fV.data[5]);
00257                         temp.r7 = float(-fV.data[6]); temp.r8 = float(-fV.data[7]); temp.r9 = float(fV.data[8]);
00258                         Math3d::MulMatMat(temp, transU, R);
00259                         // estimate current translation
00260                         t = tEstimate(R);
00261                 }
00262         }
00263         else
00264         {
00265                 // R = [V(:, 1:2) -V(:, 3)] * U'
00266                 temp.r1 = float(fV.data[0]); temp.r2 = float(fV.data[1]); temp.r3 = float(-fV.data[2]);
00267                 temp.r4 = float(fV.data[3]); temp.r5 = float(fV.data[4]); temp.r6 = float(-fV.data[5]);
00268                 temp.r7 = float(fV.data[6]); temp.r8 = float(fV.data[7]); temp.r9 = float(-fV.data[8]);
00269                 Math3d::MulMatMat(temp, transU, R);
00270                 // estimate current translation
00271                 t = tEstimate(R);
00272 
00273                 if (t.z < 0) // we need to invert t (object should be in front of the camera)
00274                 {
00275                         // R = -V * U'
00276                         temp.r1 = float(-fV.data[0]); temp.r2 = float(-fV.data[1]); temp.r3 = float(-fV.data[2]);
00277                         temp.r4 = float(-fV.data[3]); temp.r5 = float(-fV.data[4]); temp.r6 = float(-fV.data[5]);
00278                         temp.r7 = float(-fV.data[6]); temp.r8 = float(-fV.data[7]); temp.r9 = float(-fV.data[8]);
00279                         Math3d::MulMatMat(temp, transU, R);
00280                         // estimate current translation
00281                         t = tEstimate(R);
00282                 }
00283         }
00284 
00285         // calculate current Q
00286         for (i = 0; i < m_nPoints; i++)
00287         {
00288                 // Q(:, i) = R * P(: , i) + t
00289                 Math3d::MulMatVec(R, m_pP[i], m_pQ[i]);
00290                 Math3d::AddVecVec(m_pQ[i], t, m_pQ[i]);
00291         }
00292 
00293         // calculate error
00294         error = 0.0f;
00295         Vec3d vec;
00296 
00297         for (i = 0; i < m_nPoints; i++)
00298         {
00299                 // (eye(3) - F(:, :, i)) * Q(:, i)
00300                 Math3d::SubtractMatMat(Math3d::unit_mat, m_pF[i], temp);
00301                 Math3d::MulMatVec(temp, m_pQ[i], vec);
00302 
00303                 error += Math3d::SquaredLength(vec);
00304         }
00305 }
00306 
00307 Vec3d CObjectPose::tEstimate(Mat3d &R)
00308 {
00309         Vec3d sum = Math3d::zero_vec;
00310         Vec3d temp;
00311 
00312         // sum = sum + F(:, :, i) * R * P(:, i)
00313         for (int i = 0; i < m_nPoints; i++)
00314         {
00315                 Math3d::MulMatVec(R, m_pP[i], temp);
00316                 Math3d::MulMatVec(m_pF[i], temp, temp);
00317                 Math3d::AddToVec(sum, temp);
00318         }
00319 
00320         Math3d::MulMatVec(m_tFactor, sum, sum);
00321 
00322         return sum;
00323 }


asr_ivt
Author(s): Allgeyer Tobias, Hutmacher Robin, Kleinert Daniel, Meißner Pascal, Scholz Jonas, Stöckle Patrick
autogenerated on Thu Jun 6 2019 21:46:57