Path: blob/master/modules/calib3d/test/test_cameracalibration_tilt.cpp
16337 views
/*M///////////////////////////////////////////////////////////////////////////////////////1//2// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.3//4// By downloading, copying, installing or using the software you agree to this license.5// If you do not agree to this license, do not download, install,6// copy or use the software.7//8//9// License Agreement10// For Open Source Computer Vision Library11//12// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.13// Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved.14// Third party copyrights are property of their respective owners.15//16// Redistribution and use in source and binary forms, with or without modification,17// are permitted provided that the following conditions are met:18//19// * Redistribution's of source code must retain the above copyright notice,20// this list of conditions and the following disclaimer.21//22// * Redistribution's in binary form must reproduce the above copyright notice,23// this list of conditions and the following disclaimer in the documentation24// and/or other materials provided with the distribution.25//26// * The name of the copyright holders may not be used to endorse or promote products27// derived from this software without specific prior written permission.28//29// This software is provided by the copyright holders and contributors "as is" and30// any express or implied warranties, including, but not limited to, the implied31// warranties of merchantability and fitness for a particular purpose are disclaimed.32// In no event shall the Intel Corporation or contributors be liable for any direct,33// indirect, incidental, special, exemplary, or consequential damages34// (including, but not limited to, procurement of substitute goods or services;35// loss of use, data, or profits; or business interruption) however caused36// and on any theory of liability, whether in contract, strict liability,37// or tort (including negligence or otherwise) arising in any way out of38// the use of this software, even if advised of the possibility of such damage.39//40//M*/4142#include "test_precomp.hpp"43#include "opencv2/ts/cuda_test.hpp" // EXPECT_MAT_NEAR4445namespace opencv_test { namespace {4647#define NUM_DIST_COEFF_TILT 144849/**50Some conventions:51- the first camera determines the world coordinate system52- y points down, hence top means minimal y value (negative) and53bottom means maximal y value (positive)54- the field of view plane is tilted around x such that it55intersects the xy-plane in a line with a large (positive)56y-value57- image sensor and object are both modelled in the halfspace58z > 0596061**/62class cameraCalibrationTiltTest : public ::testing::Test {6364protected:65cameraCalibrationTiltTest()66: m_toRadian(acos(-1.0)/180.0)67, m_toDegree(180.0/acos(-1.0))68{}69virtual void SetUp();7071protected:72static const cv::Size m_imageSize;73static const double m_pixelSize;74static const double m_circleConfusionPixel;75static const double m_lensFocalLength;76static const double m_lensFNumber;77static const double m_objectDistance;78static const double m_planeTiltDegree;79static const double m_pointTargetDist;80static const int m_pointTargetNum;8182/** image distance corresponding to working distance */83double m_imageDistance;84/** image tilt angle corresponding to the tilt of the object plane */85double m_imageTiltDegree;86/** center of the field of view, near and far plane */87std::vector<cv::Vec3d> m_fovCenter;88/** normal of the field of view, near and far plane */89std::vector<cv::Vec3d> m_fovNormal;90/** points on a plane calibration target */91std::vector<cv::Point3d> m_pointTarget;92/** rotations for the calibration target */93std::vector<cv::Vec3d> m_pointTargetRvec;94/** translations for the calibration target */95std::vector<cv::Vec3d> m_pointTargetTvec;96/** camera matrix */97cv::Matx33d m_cameraMatrix;98/** distortion coefficients */99cv::Vec<double, NUM_DIST_COEFF_TILT> m_distortionCoeff;100101/** random generator */102cv::RNG m_rng;103/** degree to radian conversion factor */104const double m_toRadian;105/** radian to degree conversion factor */106const double m_toDegree;107108/**109computes for a given distance of an image or object point110the distance of the corresponding object or image point111*/112double opticalMap(double dist) {113return m_lensFocalLength*dist/(dist - m_lensFocalLength);114}115116/** magnification of the optical map */117double magnification(double dist) {118return m_lensFocalLength/(dist - m_lensFocalLength);119}120121/**122Changes given distortion coefficients randomly by adding123a uniformly distributed random variable in [-max max]124\param coeff input125\param max limits for the random variables126*/127void randomDistortionCoeff(128cv::Vec<double, NUM_DIST_COEFF_TILT>& coeff,129const cv::Vec<double, NUM_DIST_COEFF_TILT>& max)130{131for (int i = 0; i < coeff.rows; ++i)132coeff(i) += m_rng.uniform(-max(i), max(i));133}134135/** numerical jacobian */136void numericalDerivative(137cv::Mat& jac,138double eps,139const std::vector<cv::Point3d>& obj,140const cv::Vec3d& rvec,141const cv::Vec3d& tvec,142const cv::Matx33d& camera,143const cv::Vec<double, NUM_DIST_COEFF_TILT>& distor);144145/** remove points with projection outside the sensor array */146void removeInvalidPoints(147std::vector<cv::Point2d>& imagePoints,148std::vector<cv::Point3d>& objectPoints);149150/** add uniform distribute noise in [-halfWidthNoise, halfWidthNoise]151to the image points and remove out of range points */152void addNoiseRemoveInvalidPoints(153std::vector<cv::Point2f>& imagePoints,154std::vector<cv::Point3f>& objectPoints,155std::vector<cv::Point2f>& noisyImagePoints,156double halfWidthNoise);157};158159/** Number of Pixel of the sensor */160const cv::Size cameraCalibrationTiltTest::m_imageSize(1600, 1200);161/** Size of a pixel in mm */162const double cameraCalibrationTiltTest::m_pixelSize(.005);163/** Diameter of the circle of confusion */164const double cameraCalibrationTiltTest::m_circleConfusionPixel(3);165/** Focal length of the lens */166const double cameraCalibrationTiltTest::m_lensFocalLength(16.4);167/** F-Number */168const double cameraCalibrationTiltTest::m_lensFNumber(8);169/** Working distance */170const double cameraCalibrationTiltTest::m_objectDistance(200);171/** Angle between optical axis and object plane normal */172const double cameraCalibrationTiltTest::m_planeTiltDegree(55);173/** the calibration target are points on a square grid with this side length */174const double cameraCalibrationTiltTest::m_pointTargetDist(5);175/** the calibration target has (2*n + 1) x (2*n + 1) points */176const int cameraCalibrationTiltTest::m_pointTargetNum(15);177178179void cameraCalibrationTiltTest::SetUp()180{181m_imageDistance = opticalMap(m_objectDistance);182m_imageTiltDegree = m_toDegree * atan2(183m_imageDistance * tan(m_toRadian * m_planeTiltDegree),184m_objectDistance);185// half sensor height186double tmp = .5 * (m_imageSize.height - 1) * m_pixelSize187* cos(m_toRadian * m_imageTiltDegree);188// y-Value of tilted sensor189double yImage[2] = {tmp, -tmp};190// change in z because of the tilt191tmp *= sin(m_toRadian * m_imageTiltDegree);192// z-values of the sensor lower and upper corner193double zImage[2] = {194m_imageDistance + tmp,195m_imageDistance - tmp};196// circle of confusion197double circleConfusion = m_circleConfusionPixel*m_pixelSize;198// aperture of the lense199double aperture = m_lensFocalLength/m_lensFNumber;200// near and far factor on the image side201double nearFarFactorImage[2] = {202aperture/(aperture - circleConfusion),203aperture/(aperture + circleConfusion)};204// on the object side - points that determine the field of205// view206std::vector<cv::Vec3d> fovBottomTop(6);207std::vector<cv::Vec3d>::iterator itFov = fovBottomTop.begin();208for (size_t iBottomTop = 0; iBottomTop < 2; ++iBottomTop)209{210// mapping sensor to field of view211*itFov = cv::Vec3d(0,yImage[iBottomTop],zImage[iBottomTop]);212*itFov *= magnification((*itFov)(2));213++itFov;214for (size_t iNearFar = 0; iNearFar < 2; ++iNearFar, ++itFov)215{216// scaling to the near and far distance on the217// image side218*itFov = cv::Vec3d(0,yImage[iBottomTop],zImage[iBottomTop]) *219nearFarFactorImage[iNearFar];220// scaling to the object side221*itFov *= magnification((*itFov)(2));222}223}224m_fovCenter.resize(3);225m_fovNormal.resize(3);226for (size_t i = 0; i < 3; ++i)227{228m_fovCenter[i] = .5*(fovBottomTop[i] + fovBottomTop[i+3]);229m_fovNormal[i] = fovBottomTop[i+3] - fovBottomTop[i];230m_fovNormal[i] = cv::normalize(m_fovNormal[i]);231m_fovNormal[i] = cv::Vec3d(232m_fovNormal[i](0),233-m_fovNormal[i](2),234m_fovNormal[i](1));235// one target position in each plane236m_pointTargetTvec.push_back(m_fovCenter[i]);237cv::Vec3d rvec = cv::Vec3d(0,0,1).cross(m_fovNormal[i]);238rvec = cv::normalize(rvec);239rvec *= acos(m_fovNormal[i](2));240m_pointTargetRvec.push_back(rvec);241}242// calibration target243size_t num = 2*m_pointTargetNum + 1;244m_pointTarget.resize(num*num);245std::vector<cv::Point3d>::iterator itTarget = m_pointTarget.begin();246for (int iY = -m_pointTargetNum; iY <= m_pointTargetNum; ++iY)247{248for (int iX = -m_pointTargetNum; iX <= m_pointTargetNum; ++iX, ++itTarget)249{250*itTarget = cv::Point3d(iX, iY, 0) * m_pointTargetDist;251}252}253// oblique target positions254// approximate distance to the near and far plane255double dist = std::max(256std::abs(m_fovNormal[0].dot(m_fovCenter[0] - m_fovCenter[1])),257std::abs(m_fovNormal[0].dot(m_fovCenter[0] - m_fovCenter[2])));258// maximal angle such that target border "reaches" near and far plane259double maxAngle = atan2(dist, m_pointTargetNum*m_pointTargetDist);260std::vector<double> angle;261angle.push_back(-maxAngle);262angle.push_back(maxAngle);263cv::Matx33d baseMatrix;264cv::Rodrigues(m_pointTargetRvec.front(), baseMatrix);265for (std::vector<double>::const_iterator itAngle = angle.begin(); itAngle != angle.end(); ++itAngle)266{267cv::Matx33d rmat;268for (int i = 0; i < 2; ++i)269{270cv::Vec3d rvec(0,0,0);271rvec(i) = *itAngle;272cv::Rodrigues(rvec, rmat);273rmat = baseMatrix*rmat;274cv::Rodrigues(rmat, rvec);275m_pointTargetTvec.push_back(m_fovCenter.front());276m_pointTargetRvec.push_back(rvec);277}278}279// camera matrix280double cx = .5 * (m_imageSize.width - 1);281double cy = .5 * (m_imageSize.height - 1);282double f = m_imageDistance/m_pixelSize;283m_cameraMatrix = cv::Matx33d(284f,0,cx,2850,f,cy,2860,0,1);287// distortion coefficients288m_distortionCoeff = cv::Vec<double, NUM_DIST_COEFF_TILT>::all(0);289// tauX290m_distortionCoeff(12) = -m_toRadian*m_imageTiltDegree;291292}293294void cameraCalibrationTiltTest::numericalDerivative(295cv::Mat& jac,296double eps,297const std::vector<cv::Point3d>& obj,298const cv::Vec3d& rvec,299const cv::Vec3d& tvec,300const cv::Matx33d& camera,301const cv::Vec<double, NUM_DIST_COEFF_TILT>& distor)302{303cv::Vec3d r(rvec);304cv::Vec3d t(tvec);305cv::Matx33d cm(camera);306cv::Vec<double, NUM_DIST_COEFF_TILT> dc(distor);307double* param[10+NUM_DIST_COEFF_TILT] = {308&r(0), &r(1), &r(2),309&t(0), &t(1), &t(2),310&cm(0,0), &cm(1,1), &cm(0,2), &cm(1,2),311&dc(0), &dc(1), &dc(2), &dc(3), &dc(4), &dc(5), &dc(6),312&dc(7), &dc(8), &dc(9), &dc(10), &dc(11), &dc(12), &dc(13)};313std::vector<cv::Point2d> pix0, pix1;314double invEps = .5/eps;315316for (int col = 0; col < 10+NUM_DIST_COEFF_TILT; ++col)317{318double save = *(param[col]);319*(param[col]) = save + eps;320cv::projectPoints(obj, r, t, cm, dc, pix0);321*(param[col]) = save - eps;322cv::projectPoints(obj, r, t, cm, dc, pix1);323*(param[col]) = save;324325std::vector<cv::Point2d>::const_iterator it0 = pix0.begin();326std::vector<cv::Point2d>::const_iterator it1 = pix1.begin();327int row = 0;328for (;it0 != pix0.end(); ++it0, ++it1)329{330cv::Point2d d = invEps*(*it0 - *it1);331jac.at<double>(row, col) = d.x;332++row;333jac.at<double>(row, col) = d.y;334++row;335}336}337}338339void cameraCalibrationTiltTest::removeInvalidPoints(340std::vector<cv::Point2d>& imagePoints,341std::vector<cv::Point3d>& objectPoints)342{343// remove object and imgage points out of range344std::vector<cv::Point2d>::iterator itImg = imagePoints.begin();345std::vector<cv::Point3d>::iterator itObj = objectPoints.begin();346while (itImg != imagePoints.end())347{348bool ok =349itImg->x >= 0 &&350itImg->x <= m_imageSize.width - 1.0 &&351itImg->y >= 0 &&352itImg->y <= m_imageSize.height - 1.0;353if (ok)354{355++itImg;356++itObj;357}358else359{360itImg = imagePoints.erase(itImg);361itObj = objectPoints.erase(itObj);362}363}364}365366void cameraCalibrationTiltTest::addNoiseRemoveInvalidPoints(367std::vector<cv::Point2f>& imagePoints,368std::vector<cv::Point3f>& objectPoints,369std::vector<cv::Point2f>& noisyImagePoints,370double halfWidthNoise)371{372std::vector<cv::Point2f>::iterator itImg = imagePoints.begin();373std::vector<cv::Point3f>::iterator itObj = objectPoints.begin();374noisyImagePoints.clear();375noisyImagePoints.reserve(imagePoints.size());376while (itImg != imagePoints.end())377{378cv::Point2f pix = *itImg + cv::Point2f(379(float)m_rng.uniform(-halfWidthNoise, halfWidthNoise),380(float)m_rng.uniform(-halfWidthNoise, halfWidthNoise));381bool ok =382pix.x >= 0 &&383pix.x <= m_imageSize.width - 1.0 &&384pix.y >= 0 &&385pix.y <= m_imageSize.height - 1.0;386if (ok)387{388noisyImagePoints.push_back(pix);389++itImg;390++itObj;391}392else393{394itImg = imagePoints.erase(itImg);395itObj = objectPoints.erase(itObj);396}397}398}399400401TEST_F(cameraCalibrationTiltTest, projectPoints)402{403std::vector<cv::Point2d> imagePoints;404std::vector<cv::Point3d> objectPoints = m_pointTarget;405cv::Vec3d rvec = m_pointTargetRvec.front();406cv::Vec3d tvec = m_pointTargetTvec.front();407408cv::Vec<double, NUM_DIST_COEFF_TILT> coeffNoiseHalfWidth(409.1, .1, // k1 k2410.01, .01, // p1 p2411.001, .001, .001, .001, // k3 k4 k5 k6412.001, .001, .001, .001, // s1 s2 s3 s4413.01, .01); // tauX tauY414for (size_t numTest = 0; numTest < 10; ++numTest)415{416// create random distortion coefficients417cv::Vec<double, NUM_DIST_COEFF_TILT> distortionCoeff = m_distortionCoeff;418randomDistortionCoeff(distortionCoeff, coeffNoiseHalfWidth);419420// projection421cv::projectPoints(422objectPoints,423rvec,424tvec,425m_cameraMatrix,426distortionCoeff,427imagePoints);428429// remove object and imgage points out of range430removeInvalidPoints(imagePoints, objectPoints);431432int numPoints = (int)imagePoints.size();433int numParams = 10 + distortionCoeff.rows;434cv::Mat jacobian(2*numPoints, numParams, CV_64FC1);435436// projection and jacobian437cv::projectPoints(438objectPoints,439rvec,440tvec,441m_cameraMatrix,442distortionCoeff,443imagePoints,444jacobian);445446// numerical derivatives447cv::Mat numericJacobian(2*numPoints, numParams, CV_64FC1);448double eps = 1e-7;449numericalDerivative(450numericJacobian,451eps,452objectPoints,453rvec,454tvec,455m_cameraMatrix,456distortionCoeff);457458#if 0459for (size_t row = 0; row < 2; ++row)460{461std::cout << "------ Row = " << row << " ------\n";462for (size_t i = 0; i < 10+NUM_DIST_COEFF_TILT; ++i)463{464std::cout << i465<< " jac = " << jacobian.at<double>(row,i)466<< " num = " << numericJacobian.at<double>(row,i)467<< " rel. diff = " << abs(numericJacobian.at<double>(row,i) - jacobian.at<double>(row,i))/abs(numericJacobian.at<double>(row,i))468<< "\n";469}470}471#endif472// relative difference for large values (rvec and tvec)473cv::Mat check = abs(jacobian(cv::Range::all(), cv::Range(0,6)) - numericJacobian(cv::Range::all(), cv::Range(0,6)))/474(1 + abs(jacobian(cv::Range::all(), cv::Range(0,6))));475double minVal, maxVal;476cv::minMaxIdx(check, &minVal, &maxVal);477EXPECT_LE(maxVal, .01);478// absolute difference for distortion and camera matrix479EXPECT_MAT_NEAR(jacobian(cv::Range::all(), cv::Range(6,numParams)), numericJacobian(cv::Range::all(), cv::Range(6,numParams)), 1e-5);480}481}482483TEST_F(cameraCalibrationTiltTest, undistortPoints)484{485cv::Vec<double, NUM_DIST_COEFF_TILT> coeffNoiseHalfWidth(486.2, .1, // k1 k2487.01, .01, // p1 p2488.01, .01, .01, .01, // k3 k4 k5 k6489.001, .001, .001, .001, // s1 s2 s3 s4490.001, .001); // tauX tauY491double step = 99;492double toleranceBackProjection = 1e-5;493494for (size_t numTest = 0; numTest < 10; ++numTest)495{496cv::Vec<double, NUM_DIST_COEFF_TILT> distortionCoeff = m_distortionCoeff;497randomDistortionCoeff(distortionCoeff, coeffNoiseHalfWidth);498499// distorted points500std::vector<cv::Point2d> distorted;501for (double x = 0; x <= m_imageSize.width-1; x += step)502for (double y = 0; y <= m_imageSize.height-1; y += step)503distorted.push_back(cv::Point2d(x,y));504std::vector<cv::Point2d> normalizedUndistorted;505506// undistort507cv::undistortPoints(distorted,508normalizedUndistorted,509m_cameraMatrix,510distortionCoeff);511512// copy normalized points to 3D513std::vector<cv::Point3d> objectPoints;514for (std::vector<cv::Point2d>::const_iterator itPnt = normalizedUndistorted.begin();515itPnt != normalizedUndistorted.end(); ++itPnt)516objectPoints.push_back(cv::Point3d(itPnt->x, itPnt->y, 1));517518// project519std::vector<cv::Point2d> imagePoints(objectPoints.size());520cv::projectPoints(objectPoints,521cv::Vec3d(0,0,0),522cv::Vec3d(0,0,0),523m_cameraMatrix,524distortionCoeff,525imagePoints);526527EXPECT_MAT_NEAR(distorted, imagePoints, toleranceBackProjection);528}529}530531template <typename INPUT, typename ESTIMATE>532void show(const std::string& name, const INPUT in, const ESTIMATE est)533{534std::cout << name << " = " << est << " (init = " << in535<< ", diff = " << est-in << ")\n";536}537538template <typename INPUT>539void showVec(const std::string& name, const INPUT& in, const cv::Mat& est)540{541542for (size_t i = 0; i < in.channels; ++i)543{544std::stringstream ss;545ss << name << "[" << i << "]";546show(ss.str(), in(i), est.at<double>(i));547}548}549550/**551For given camera matrix and distortion coefficients552- project point target in different positions onto the sensor553- add pixel noise554- estimate camera model with noisy measurements555- compare result with initial model parameter556557Parameter are differently affected by the noise558*/559TEST_F(cameraCalibrationTiltTest, calibrateCamera)560{561cv::Vec<double, NUM_DIST_COEFF_TILT> coeffNoiseHalfWidth(562.2, .1, // k1 k2563.01, .01, // p1 p25640, 0, 0, 0, // k3 k4 k5 k6565.001, .001, .001, .001, // s1 s2 s3 s4566.001, .001); // tauX tauY567double pixelNoiseHalfWidth = .5;568std::vector<cv::Point3f> pointTarget;569pointTarget.reserve(m_pointTarget.size());570for (std::vector<cv::Point3d>::const_iterator it = m_pointTarget.begin(); it != m_pointTarget.end(); ++it)571pointTarget.push_back(cv::Point3f(572(float)(it->x),573(float)(it->y),574(float)(it->z)));575576for (size_t numTest = 0; numTest < 5; ++numTest)577{578// create random distortion coefficients579cv::Vec<double, NUM_DIST_COEFF_TILT> distortionCoeff = m_distortionCoeff;580randomDistortionCoeff(distortionCoeff, coeffNoiseHalfWidth);581582// container for calibration data583std::vector<std::vector<cv::Point3f> > viewsObjectPoints;584std::vector<std::vector<cv::Point2f> > viewsImagePoints;585std::vector<std::vector<cv::Point2f> > viewsNoisyImagePoints;586587// simulate calibration data with projectPoints588std::vector<cv::Vec3d>::const_iterator itRvec = m_pointTargetRvec.begin();589std::vector<cv::Vec3d>::const_iterator itTvec = m_pointTargetTvec.begin();590// loop over different views591for (;itRvec != m_pointTargetRvec.end(); ++ itRvec, ++itTvec)592{593std::vector<cv::Point3f> objectPoints(pointTarget);594std::vector<cv::Point2f> imagePoints;595std::vector<cv::Point2f> noisyImagePoints;596// project calibration target to sensor597cv::projectPoints(598objectPoints,599*itRvec,600*itTvec,601m_cameraMatrix,602distortionCoeff,603imagePoints);604// remove invisible points605addNoiseRemoveInvalidPoints(606imagePoints,607objectPoints,608noisyImagePoints,609pixelNoiseHalfWidth);610// add data for view611viewsNoisyImagePoints.push_back(noisyImagePoints);612viewsImagePoints.push_back(imagePoints);613viewsObjectPoints.push_back(objectPoints);614}615616// Output617std::vector<cv::Mat> outRvecs, outTvecs;618cv::Mat outCameraMatrix(3, 3, CV_64F, cv::Scalar::all(1)), outDistCoeff;619620// Stopping criteria621cv::TermCriteria stop(622cv::TermCriteria::COUNT+cv::TermCriteria::EPS,62350000,6241e-14);625// model choice626int flag =627cv::CALIB_FIX_ASPECT_RATIO |628// cv::CALIB_RATIONAL_MODEL |629cv::CALIB_FIX_K3 |630// cv::CALIB_FIX_K6 |631cv::CALIB_THIN_PRISM_MODEL |632cv::CALIB_TILTED_MODEL;633// estimate634double backProjErr = cv::calibrateCamera(635viewsObjectPoints,636viewsNoisyImagePoints,637m_imageSize,638outCameraMatrix,639outDistCoeff,640outRvecs,641outTvecs,642flag,643stop);644645EXPECT_LE(backProjErr, pixelNoiseHalfWidth);646647#if 0648std::cout << "------ estimate ------\n";649std::cout << "back projection error = " << backProjErr << "\n";650std::cout << "points per view = {" << viewsObjectPoints.front().size();651for (size_t i = 1; i < viewsObjectPoints.size(); ++i)652std::cout << ", " << viewsObjectPoints[i].size();653std::cout << "}\n";654show("fx", m_cameraMatrix(0,0), outCameraMatrix.at<double>(0,0));655show("fy", m_cameraMatrix(1,1), outCameraMatrix.at<double>(1,1));656show("cx", m_cameraMatrix(0,2), outCameraMatrix.at<double>(0,2));657show("cy", m_cameraMatrix(1,2), outCameraMatrix.at<double>(1,2));658showVec("distor", distortionCoeff, outDistCoeff);659#endif660if (pixelNoiseHalfWidth > 0)661{662double tolRvec = pixelNoiseHalfWidth;663double tolTvec = m_objectDistance * tolRvec;664// back projection error665for (size_t i = 0; i < viewsNoisyImagePoints.size(); ++i)666{667double dRvec = cv::norm(m_pointTargetRvec[i],668cv::Vec3d(outRvecs[i].at<double>(0), outRvecs[i].at<double>(1), outRvecs[i].at<double>(2))669);670EXPECT_LE(dRvec, tolRvec);671double dTvec = cv::norm(m_pointTargetTvec[i],672cv::Vec3d(outTvecs[i].at<double>(0), outTvecs[i].at<double>(1), outTvecs[i].at<double>(2))673);674EXPECT_LE(dTvec, tolTvec);675676std::vector<cv::Point2f> backProjection;677cv::projectPoints(678viewsObjectPoints[i],679outRvecs[i],680outTvecs[i],681outCameraMatrix,682outDistCoeff,683backProjection);684EXPECT_MAT_NEAR(backProjection, viewsNoisyImagePoints[i], 1.5*pixelNoiseHalfWidth);685EXPECT_MAT_NEAR(backProjection, viewsImagePoints[i], 1.5*pixelNoiseHalfWidth);686}687}688pixelNoiseHalfWidth *= .25;689}690}691692}} // namespace693694695