1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-27 22:33:03 +04:00
Files
opencv/modules/calib/test/test_cameracalibration.cpp
Alexander Smorkalov e19b0ebc5c Merge pull request #28804 from asmorkalov:as/calib_boards_migration
Migrated chessboard and circles grid detectors to objdetect #28804
  
OpenCV Contrib: https://github.com/opencv/opencv_contrib/pull/4125
OpenCV Extra: https://github.com/opencv/opencv_extra/pull/1375

### Pull Request Readiness Checklist

See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request

- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [ ] The PR is proposed to the proper branch
- [ ] There is a reference to the original bug report and related work
- [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
      Patch to opencv_extra has the same branch name.
- [ ] The feature is well documented and sample code can be built with the project CMake
2026-05-27 16:06:51 +03:00

1902 lines
76 KiB
C++

/*M///////////////////////////////////////////////////////////////////////////////////////
//
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// Intel License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000, Intel Corporation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of Intel Corporation may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include "test_precomp.hpp"
#include "opencv2/stereo.hpp"
#include "opencv2/objdetect.hpp"
namespace opencv_test { namespace {
// --------------------------------- CV_CameraCalibrationTest --------------------------------------------
typedef Matx33d RotMat;
class CV_CameraCalibrationTest : public cvtest::BaseTest
{
public:
CV_CameraCalibrationTest();
~CV_CameraCalibrationTest();
void clear();
protected:
int compare(double* val, double* refVal, int len,
double eps, const char* paramName);
virtual void calibrate(Size imageSize,
const std::vector<std::vector<Point2d> >& imagePoints,
const std::vector<std::vector<Point3d> >& objectPoints,
int iFixedPoint, Mat& distortionCoeffs, Mat& cameraMatrix, std::vector<Vec3d>& translationVectors,
std::vector<RotMat>& rotationMatrices, std::vector<Point3d>& newObjPoints,
std::vector<double>& stdDevs, std::vector<double>& perViewErrors,
int flags ) = 0;
virtual void project( const std::vector<Point3d>& objectPoints,
const RotMat& rotationMatrix, const Vec3d& translationVector,
const Mat& cameraMatrix, const Mat& distortion,
std::vector<Point2d>& imagePoints ) = 0;
void run(int);
};
CV_CameraCalibrationTest::CV_CameraCalibrationTest()
{
}
CV_CameraCalibrationTest::~CV_CameraCalibrationTest()
{
clear();
}
void CV_CameraCalibrationTest::clear()
{
cvtest::BaseTest::clear();
}
int CV_CameraCalibrationTest::compare(double* val, double* ref_val, int len,
double eps, const char* param_name )
{
return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name );
}
void CV_CameraCalibrationTest::run( int start_from )
{
int code = cvtest::TS::OK;
cv::String filepath;
cv::String filename;
std::vector<std::vector<Point2d> > imagePoints;
std::vector<std::vector<Point3d> > objectPoints;
std::vector<std::vector<Point2d> > reprojectPoints;
std::vector<Vec3d> transVects;
std::vector<RotMat> rotMatrs;
std::vector<Point3d> newObjPoints;
std::vector<double> stdDevs;
std::vector<double> perViewErrors;
std::vector<Vec3d> goodTransVects;
std::vector<RotMat> goodRotMatrs;
std::vector<Point3d> goodObjPoints;
std::vector<double> goodPerViewErrors;
std::vector<double> goodStdDevs;
Mat cameraMatrix;
Mat distortion = Mat::zeros(1, 5, CV_64F);
Mat goodDistortion = Mat::zeros(1, 5, CV_64F);
FILE* file = 0;
FILE* datafile = 0;
int i,j;
int currImage;
int currPoint;
char i_dat_file[100];
int progress = 0;
int values_read = -1;
filepath = cv::format("%scv/cameracalibration/", ts->get_data_path().c_str() );
filename = cv::format("%sdatafiles.txt", filepath.c_str() );
datafile = fopen( filename.c_str(), "r" );
if( datafile == 0 )
{
ts->printf( cvtest::TS::LOG, "Could not open file with list of test files: %s\n", filename.c_str() );
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
ts->set_failed_test_info( code );
return;
}
int numTests = 0;
values_read = fscanf(datafile,"%d",&numTests);
CV_Assert(values_read == 1);
for( int currTest = start_from; currTest < numTests; currTest++ )
{
values_read = fscanf(datafile,"%s",i_dat_file);
CV_Assert(values_read == 1);
filename = cv::format("%s%s", filepath.c_str(), i_dat_file);
file = fopen(filename.c_str(),"r");
ts->update_context( this, currTest, true );
if( file == 0 )
{
ts->printf( cvtest::TS::LOG,
"Can't open current test file: %s\n",filename.c_str());
if( numTests == 1 )
{
code = cvtest::TS::FAIL_MISSING_TEST_DATA;
break;
}
continue; // if there is more than one test, just skip the test
}
Size imageSize;
values_read = fscanf(file,"%d %d\n",&(imageSize.width),&(imageSize.height));
CV_Assert(values_read == 2);
if( imageSize.width <= 0 || imageSize.height <= 0 )
{
ts->printf( cvtest::TS::LOG, "Image size in test file is incorrect\n" );
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
break;
}
/* Read etalon size */
Size etalonSize;
values_read = fscanf(file,"%d %d\n",&(etalonSize.width),&(etalonSize.height));
CV_Assert(values_read == 2);
if( etalonSize.width <= 0 || etalonSize.height <= 0 )
{
ts->printf( cvtest::TS::LOG, "Pattern size in test file is incorrect\n" );
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
break;
}
int numPoints = etalonSize.width * etalonSize.height;
/* Read number of images */
int numImages = 0;
values_read = fscanf(file,"%d\n",&numImages);
CV_Assert(values_read == 1);
if( numImages <=0 )
{
ts->printf( cvtest::TS::LOG, "Number of images in test file is incorrect\n");
code = cvtest::TS::FAIL_INVALID_TEST_DATA;
break;
}
/* Read calibration flags */
int calibFlags = 0;
values_read = fscanf(file,"%d\n",&calibFlags);
CV_Assert(values_read == 1);
/* Read index of the fixed point */
int iFixedPoint;
values_read = fscanf(file,"%d\n",&iFixedPoint);
CV_Assert(values_read == 1);
/* Need to allocate memory */
imagePoints.resize(numImages);
objectPoints.resize(numImages);
reprojectPoints.resize(numImages);
for( currImage = 0; currImage < numImages; currImage++ )
{
imagePoints[currImage].resize(numPoints);
objectPoints[currImage].resize(numPoints);
reprojectPoints[currImage].resize(numPoints);
}
transVects.resize(numImages);
rotMatrs.resize(numImages);
newObjPoints.resize(numPoints);
stdDevs.resize(CALIB_NINTRINSIC + 6*numImages + 3*numPoints);
perViewErrors.resize(numImages);
goodTransVects.resize(numImages);
goodRotMatrs.resize(numImages);
goodObjPoints.resize(numPoints);
goodPerViewErrors.resize(numImages);
int nstddev = CALIB_NINTRINSIC + 6*numImages + 3*numPoints;
goodStdDevs.resize(nstddev);
for( currImage = 0; currImage < numImages; currImage++ )
{
for( currPoint = 0; currPoint < numPoints; currPoint++ )
{
double x,y,z;
values_read = fscanf(file,"%lf %lf %lf\n",&x,&y,&z);
CV_Assert(values_read == 3);
objectPoints[currImage][currPoint].x = x;
objectPoints[currImage][currPoint].y = y;
objectPoints[currImage][currPoint].z = z;
}
}
/* Read image points */
for( currImage = 0; currImage < numImages; currImage++ )
{
for( currPoint = 0; currPoint < numPoints; currPoint++ )
{
double x,y;
values_read = fscanf(file,"%lf %lf\n",&x,&y);
CV_Assert(values_read == 2);
imagePoints[currImage][currPoint].x = x;
imagePoints[currImage][currPoint].y = y;
}
}
/* Read good data computed before */
/* Focal lengths */
double goodFcx,goodFcy;
values_read = fscanf(file,"%lf %lf",&goodFcx,&goodFcy);
CV_Assert(values_read == 2);
/* Principal points */
double goodCx,goodCy;
values_read = fscanf(file,"%lf %lf",&goodCx,&goodCy);
CV_Assert(values_read == 2);
/* Read distortion */
for( i = 0; i < 4; i++ )
{
values_read = fscanf(file,"%lf",&goodDistortion.at<double>(i)); CV_Assert(values_read == 1);
}
/* Read good Rot matrices */
for( currImage = 0; currImage < numImages; currImage++ )
{
for( i = 0; i < 3; i++ )
for( j = 0; j < 3; j++ )
{
// Yes, load with transpose
values_read = fscanf(file, "%lf", &goodRotMatrs[currImage].val[j*3+i]);
CV_Assert(values_read == 1);
}
}
/* Read good Trans vectors */
for( currImage = 0; currImage < numImages; currImage++ )
{
for( i = 0; i < 3; i++ )
{
values_read = fscanf(file, "%lf", &goodTransVects[currImage].val[i]);
CV_Assert(values_read == 1);
}
}
bool releaseObject = iFixedPoint > 0 && iFixedPoint < numPoints - 1;
/* Read good refined 3D object points */
if( releaseObject )
{
for( i = 0; i < numPoints; i++ )
{
for( j = 0; j < 3; j++ )
{
values_read = fscanf(file, "%lf", &goodObjPoints[i].x + j);
CV_Assert(values_read == 1);
}
}
}
/* Read good stdDeviations */
for (i = 0; i < CALIB_NINTRINSIC + numImages*6; i++)
{
values_read = fscanf(file, "%lf", &goodStdDevs[i]);
CV_Assert(values_read == 1);
}
for( ; i < nstddev; i++ )
{
if( releaseObject )
{
values_read = fscanf(file, "%lf", &goodStdDevs[i]);
CV_Assert(values_read == 1);
}
else
goodStdDevs[i] = 0.0;
}
cameraMatrix = Mat::zeros(3, 3, CV_64F);
cameraMatrix.at<double>(0, 0) = cameraMatrix.at<double>(1, 1) = 807.;
cameraMatrix.at<double>(0, 2) = (imageSize.width - 1)*0.5;
cameraMatrix.at<double>(1, 2) = (imageSize.height - 1)*0.5;
cameraMatrix.at<double>(2, 2) = 1.;
/* Now we can calibrate camera */
calibrate( imageSize,
imagePoints,
objectPoints,
iFixedPoint,
distortion,
cameraMatrix,
transVects,
rotMatrs,
newObjPoints,
stdDevs,
perViewErrors,
calibFlags );
/* ---- Reproject points to the image ---- */
for( currImage = 0; currImage < numImages; currImage++ )
{
if( releaseObject )
{
objectPoints[currImage] = newObjPoints;
}
project( objectPoints[currImage],
rotMatrs[currImage],
transVects[currImage],
cameraMatrix,
distortion,
reprojectPoints[currImage]);
}
/* ----- Compute reprojection error ----- */
double dx,dy;
double rx,ry;
for( currImage = 0; currImage < numImages; currImage++ )
{
double imageMeanDx = 0;
double imageMeanDy = 0;
for( currPoint = 0; currPoint < etalonSize.width * etalonSize.height; currPoint++ )
{
rx = reprojectPoints[currImage][currPoint].x;
ry = reprojectPoints[currImage][currPoint].y;
dx = rx - imagePoints[currImage][currPoint].x;
dy = ry - imagePoints[currImage][currPoint].y;
imageMeanDx += dx*dx;
imageMeanDy += dy*dy;
}
goodPerViewErrors[currImage] = sqrt( (imageMeanDx + imageMeanDy) /
(etalonSize.width * etalonSize.height));
//only for c-version of test (it does not provides evaluation of perViewErrors
//and returns zeros)
if(perViewErrors[currImage] == 0.0)
perViewErrors[currImage] = goodPerViewErrors[currImage];
}
/* ========= Compare parameters ========= */
CV_Assert(cameraMatrix.type() == CV_64F && cameraMatrix.size() == Size(3, 3));
CV_Assert(distortion.type() == CV_64F);
Size dsz = distortion.size();
CV_Assert(dsz == Size(4, 1) || dsz == Size(1, 4) || dsz == Size(5, 1) || dsz == Size(1, 5));
/*std::cout << "cameraMatrix: " << cameraMatrix << "\n";
std::cout << "curr distCoeffs: " << distortion << "\n";
std::cout << "good distCoeffs: " << goodDistortion << "\n";*/
/* ----- Compare focal lengths ----- */
code = compare(&cameraMatrix.at<double>(0, 0), &goodFcx, 1, 0.1, "fx");
if( code < 0 )
break;
code = compare(&cameraMatrix.at<double>(1, 1),&goodFcy, 1, 0.1, "fy");
if( code < 0 )
break;
/* ----- Compare principal points ----- */
code = compare(&cameraMatrix.at<double>(0,2), &goodCx, 1, 0.1, "cx");
if( code < 0 )
break;
code = compare(&cameraMatrix.at<double>(1,2), &goodCy, 1, 0.1, "cy");
if( code < 0 )
break;
/* ----- Compare distortion ----- */
code = compare(&distortion.at<double>(0), &goodDistortion.at<double>(0), 4, 0.1, "[k1,k2,p1,p2]");
if( code < 0 )
break;
/* ----- Compare rot matrices ----- */
CV_Assert(rotMatrs.size() == (size_t)numImages);
CV_Assert(transVects.size() == (size_t)numImages);
//code = compare(rotMatrs[0].val, goodRotMatrs[0].val, 9*numImages, 0.05, "rotation matrices");
for( i = 0; i < numImages; i++ )
{
if( cv::norm(rotMatrs[i], goodRotMatrs[i], NORM_INF) > 0.05 )
{
printf("rot mats for frame #%d are very different\n", i);
std::cout << "curr:\n" << rotMatrs[i] << std::endl;
std::cout << "good:\n" << goodRotMatrs[i] << std::endl;
code = TS::FAIL_BAD_ACCURACY;
break;
}
}
if( code < 0 )
break;
/* ----- Compare rot matrices ----- */
code = compare(transVects[0].val, goodTransVects[0].val, 3*numImages, 0.1, "translation vectors");
if( code < 0 )
break;
/* ----- Compare refined 3D object points ----- */
if( releaseObject )
{
code = compare(&newObjPoints[0].x, &goodObjPoints[0].x, 3*numPoints, 0.1, "refined 3D object points");
if( code < 0 )
break;
}
/* ----- Compare per view re-projection errors ----- */
CV_Assert(perViewErrors.size() == (size_t)numImages);
code = compare(&perViewErrors[0], &goodPerViewErrors[0], numImages, 0.1, "per view errors vector");
if( code < 0 )
break;
/* ----- Compare standard deviations of parameters ----- */
if( stdDevs.size() < (size_t)nstddev )
stdDevs.resize(nstddev);
for ( i = 0; i < nstddev; i++)
{
if(stdDevs[i] == 0.0)
stdDevs[i] = goodStdDevs[i];
}
code = compare(&stdDevs[0], &goodStdDevs[0], nstddev, .5,
"stdDevs vector");
if( code < 0 )
break;
/*if( maxDx > 1.0 )
{
ts->printf( cvtest::TS::LOG,
"Error in reprojection maxDx=%f > 1.0\n",maxDx);
code = cvtest::TS::FAIL_BAD_ACCURACY; break;
}
if( maxDy > 1.0 )
{
ts->printf( cvtest::TS::LOG,
"Error in reprojection maxDy=%f > 1.0\n",maxDy);
code = cvtest::TS::FAIL_BAD_ACCURACY; break;
}*/
progress = update_progress( progress, currTest, numTests, 0 );
fclose(file);
file = 0;
}
if( file )
fclose(file);
if( datafile )
fclose(datafile);
if( code < 0 )
ts->set_failed_test_info( code );
}
// --------------------------------- CV_CameraCalibrationTest_CPP --------------------------------------------
class CV_CameraCalibrationTest_CPP : public CV_CameraCalibrationTest
{
public:
CV_CameraCalibrationTest_CPP(){}
protected:
virtual void calibrate(Size imageSize,
const std::vector<std::vector<Point2d> >& imagePoints,
const std::vector<std::vector<Point3d> >& objectPoints,
int iFixedPoint, Mat& distortionCoeffs, Mat& cameraMatrix, std::vector<Vec3d>& translationVectors,
std::vector<RotMat>& rotationMatrices, std::vector<Point3d>& newObjPoints,
std::vector<double>& stdDevs, std::vector<double>& perViewErrors,
int flags );
virtual void project( const std::vector<Point3d>& objectPoints,
const RotMat& rotationMatrix, const Vec3d& translationVector,
const Mat& cameraMatrix, const Mat& distortion,
std::vector<Point2d>& imagePoints );
};
void CV_CameraCalibrationTest_CPP::calibrate(Size imageSize,
const std::vector<std::vector<Point2d> >& _imagePoints,
const std::vector<std::vector<Point3d> >& _objectPoints,
int iFixedPoint, Mat& _distCoeffs, Mat& _cameraMatrix, std::vector<Vec3d>& translationVectors,
std::vector<RotMat>& rotationMatrices, std::vector<Point3d>& newObjPoints,
std::vector<double>& stdDevs, std::vector<double>& perViewErrors,
int flags )
{
int pointCount = (int)_imagePoints[0].size();
size_t i, imageCount = _imagePoints.size();
vector<vector<Point3f> > objectPoints( imageCount );
vector<vector<Point2f> > imagePoints( imageCount );
Mat cameraMatrix, distCoeffs(1,4,CV_64F,Scalar::all(0));
vector<Mat> rvecs, tvecs;
Mat newObjMat;
Mat stdDevsMatInt, stdDevsMatExt;
Mat stdDevsMatObj;
Mat perViewErrorsMat;
for( i = 0; i < imageCount; i++ )
{
Mat(_imagePoints[i]).convertTo(imagePoints[i], CV_32F);
Mat(_objectPoints[i]).convertTo(objectPoints[i], CV_32F);
}
size_t nstddev0 = CALIB_NINTRINSIC + imageCount*6, nstddev1 = nstddev0 + _imagePoints[0].size()*3;
for( i = nstddev0; i < nstddev1; i++ )
{
stdDevs[i] = 0.0;
}
calibrateCameraRO( objectPoints,
imagePoints,
imageSize,
iFixedPoint,
cameraMatrix,
distCoeffs,
rvecs,
tvecs,
newObjMat,
stdDevsMatInt,
stdDevsMatExt,
stdDevsMatObj,
perViewErrorsMat,
flags );
bool releaseObject = iFixedPoint > 0 && iFixedPoint < pointCount - 1;
if( releaseObject )
{
newObjMat.convertTo( newObjPoints, CV_64F );
}
Mat stdDevMats[] = {stdDevsMatInt, stdDevsMatExt, stdDevsMatObj}, stdDevsMat;
vconcat(stdDevMats, releaseObject ? 3 : 2, stdDevsMat);
stdDevsMat.convertTo(stdDevs, CV_64F);
perViewErrorsMat.convertTo(perViewErrors, CV_64F);
cameraMatrix.convertTo(_cameraMatrix, CV_64F);
distCoeffs.convertTo(_distCoeffs, CV_64F);
for( i = 0; i < imageCount; i++ )
{
Mat r9;
Rodrigues( rvecs[i], r9 );
r9.convertTo(rotationMatrices[i], CV_64F);
tvecs[i].convertTo(translationVectors[i], CV_64F);
}
}
void CV_CameraCalibrationTest_CPP::project( const std::vector<Point3d>& objectPoints,
const RotMat& rotationMatrix, const Vec3d& translationVector,
const Mat& cameraMatrix, const Mat& distortion,
std::vector<Point2d>& imagePoints )
{
projectPoints(objectPoints, rotationMatrix, translationVector, cameraMatrix, distortion, imagePoints );
/*Mat objectPoints( pointCount, 3, CV_64FC1, _objectPoints );
Mat rmat( 3, 3, CV_64FC1, rotationMatrix ),
rvec( 1, 3, CV_64FC1 ),
tvec( 1, 3, CV_64FC1, translationVector );
Mat cameraMatrix( 3, 3, CV_64FC1, _cameraMatrix );
Mat distCoeffs( 1, 4, CV_64FC1, distortion );
vector<Point2f> imagePoints;
cvtest::Rodrigues( rmat, rvec );
objectPoints.convertTo( objectPoints, CV_32FC1 );
projectPoints( objectPoints, rvec, tvec,
cameraMatrix, distCoeffs, imagePoints );
vector<Point2f>::const_iterator it = imagePoints.begin();
for( int i = 0; it != imagePoints.end(); ++it, i++ )
{
_imagePoints[i] = cvPoint2D64f( it->x, it->y );
}*/
}
///////////////////////////////// Stereo Calibration /////////////////////////////////////
class CV_StereoCalibrationTest : public cvtest::BaseTest
{
public:
CV_StereoCalibrationTest();
~CV_StereoCalibrationTest();
void clear();
protected:
// covers of tested functions
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags ) = 0;
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
Size imageSize, const Mat& R, const Mat& T,
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
double alpha, Size newImageSize,
Rect* validPixROI1, Rect* validPixROI2, int flags ) = 0;
virtual bool rectifyUncalibrated( const Mat& points1,
const Mat& points2, const Mat& F, Size imgSize,
Mat& H1, Mat& H2, double threshold=5 ) = 0;
virtual void triangulate( const Mat& P1, const Mat& P2,
const Mat &points1, const Mat &points2,
Mat &points4D ) = 0;
virtual void correct( const Mat& F,
const Mat &points1, const Mat &points2,
Mat &newPoints1, Mat &newPoints2 ) = 0;
int compare(double* val, double* refVal, int len,
double eps, const char* paramName);
void run(int);
};
CV_StereoCalibrationTest::CV_StereoCalibrationTest()
{
}
CV_StereoCalibrationTest::~CV_StereoCalibrationTest()
{
clear();
}
void CV_StereoCalibrationTest::clear()
{
cvtest::BaseTest::clear();
}
int CV_StereoCalibrationTest::compare(double* val, double* ref_val, int len,
double eps, const char* param_name )
{
return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name );
}
void CV_StereoCalibrationTest::run( int )
{
const int ntests = 1;
const double maxReprojErr = 2;
const double maxScanlineDistErr_c = 3;
const double maxScanlineDistErr_uc = 4;
const double maxDiffBtwRmsErrors = 1e-4;
FILE* f = 0;
for(int testcase = 1; testcase <= ntests; testcase++)
{
cv::String filepath;
char buf[1000];
filepath = cv::format("%scv/stereo/case%d/stereo_calib.txt", ts->get_data_path().c_str(), testcase );
f = fopen(filepath.c_str(), "rt");
Size patternSize;
vector<string> imglist;
if( !f || !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &patternSize.width, &patternSize.height) != 2 )
{
ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath.c_str() );
ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA );
if (f)
fclose(f);
return;
}
for(;;)
{
if( !fgets( buf, sizeof(buf)-3, f ))
break;
size_t len = strlen(buf);
while( len > 0 && isspace(buf[len-1]))
buf[--len] = '\0';
if( buf[0] == '#')
continue;
filepath = cv::format("%scv/stereo/case%d/%s", ts->get_data_path().c_str(), testcase, buf );
imglist.push_back(string(filepath));
}
fclose(f);
if( imglist.size() == 0 || imglist.size() % 2 != 0 )
{
ts->printf( cvtest::TS::LOG, "The number of images is 0 or an odd number in the case #%d\n", testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
}
int nframes = (int)(imglist.size()/2);
int npoints = patternSize.width*patternSize.height;
vector<vector<Point3f> > objpt(nframes);
vector<vector<Point2f> > imgpt1(nframes);
vector<vector<Point2f> > imgpt2(nframes);
Size imgsize;
int total = 0;
for( int i = 0; i < nframes; i++ )
{
Mat left = imread(imglist[i*2], IMREAD_GRAYSCALE);
Mat right = imread(imglist[i*2+1], IMREAD_GRAYSCALE);
if(left.empty() || right.empty())
{
ts->printf( cvtest::TS::LOG, "Can not load images %s and %s, testcase %d\n",
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
return;
}
imgsize = left.size();
bool found1 = findChessboardCorners(left, patternSize, imgpt1[i]);
bool found2 = findChessboardCorners(right, patternSize, imgpt2[i]);
cornerSubPix(left, imgpt1[i], Size(5, 5), Size(-1, -1), TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.1));
cornerSubPix(right, imgpt2[i], Size(5, 5), Size(-1, -1), TermCriteria(TermCriteria::EPS | TermCriteria::MAX_ITER, 30, 0.1));
if(!found1 || !found2)
{
ts->printf( cvtest::TS::LOG, "The function could not detect boards (%d x %d) on the images %s and %s, testcase %d\n",
patternSize.width, patternSize.height,
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
total += (int)imgpt1[i].size();
for( int j = 0; j < npoints; j++ )
objpt[i].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
}
vector<RotMat> rotMats1(nframes);
vector<Vec3d> transVecs1(nframes);
vector<RotMat> rotMats2(nframes);
vector<Vec3d> transVecs2(nframes);
vector<double> rmsErrorPerView1(nframes);
vector<double> rmsErrorPerView2(nframes);
vector<double> rmsErrorPerViewFromReprojectedImgPts1(nframes);
vector<double> rmsErrorPerViewFromReprojectedImgPts2(nframes);
// rectify (calibrated)
Mat M1 = Mat::eye(3,3,CV_64F), M2 = Mat::eye(3,3,CV_64F), D1(5,1,CV_64F), D2(5,1,CV_64F), R, T, E, F;
M1.at<double>(0,2) = M2.at<double>(0,2)=(imgsize.width-1)*0.5;
M1.at<double>(1,2) = M2.at<double>(1,2)=(imgsize.height-1)*0.5;
D1 = Scalar::all(0);
D2 = Scalar::all(0);
double rmsErrorFromStereoCalib = calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R, T, E, F,
rotMats1, transVecs1, rmsErrorPerView1, rmsErrorPerView2,
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
CALIB_SAME_FOCAL_LENGTH
//+ CALIB_FIX_ASPECT_RATIO
+ CALIB_FIX_PRINCIPAL_POINT
+ CALIB_ZERO_TANGENT_DIST
+ CALIB_FIX_K3
+ CALIB_FIX_K4 + CALIB_FIX_K5 //+ CALIB_FIX_K6
);
/* rmsErrorFromStereoCalib /= nframes*npoints; */
if (rmsErrorFromStereoCalib > maxReprojErr)
{
ts->printf(cvtest::TS::LOG, "The average reprojection error is too big (=%g), testcase %d\n",
rmsErrorFromStereoCalib, testcase);
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
double rmsErrorFromReprojectedImgPts = 0.0f;
if (rotMats1.empty() || transVecs1.empty())
{
rmsErrorPerViewFromReprojectedImgPts1 = rmsErrorPerView1;
rmsErrorPerViewFromReprojectedImgPts2 = rmsErrorPerView2;
rmsErrorFromReprojectedImgPts = rmsErrorFromStereoCalib;
}
else
{
size_t totalPoints = 0;
double totalErr[2] = { 0, 0 };
for (size_t i = 0; i < objpt.size(); ++i) {
RotMat r1 = rotMats1[i];
Vec3d t1 = transVecs1[i];
RotMat r2 = Mat(R * r1);
Mat T2t = R * t1;
Vec3d t2 = Mat(T2t + T);
vector<Point2f> reprojectedImgPts[2] = { vector<Point2f>(nframes),
vector<Point2f>(nframes) };
projectPoints(objpt[i], r1, t1, M1, D1, reprojectedImgPts[0]);
projectPoints(objpt[i], r2, t2, M2, D2, reprojectedImgPts[1]);
double viewErr[2];
viewErr[0] = cv::norm(imgpt1[i], reprojectedImgPts[0], cv::NORM_L2SQR);
viewErr[1] = cv::norm(imgpt2[i], reprojectedImgPts[1], cv::NORM_L2SQR);
size_t n = objpt[i].size();
totalErr[0] += viewErr[0];
totalErr[1] += viewErr[1];
totalPoints += n;
rmsErrorPerViewFromReprojectedImgPts1[i] = sqrt(viewErr[0] / n);
rmsErrorPerViewFromReprojectedImgPts2[i] = sqrt(viewErr[1] / n);
}
rmsErrorFromReprojectedImgPts = std::sqrt((totalErr[0] + totalErr[1]) / (2 * totalPoints));
}
if (abs(rmsErrorFromStereoCalib - rmsErrorFromReprojectedImgPts) > maxDiffBtwRmsErrors)
{
ts->printf(cvtest::TS::LOG,
"The difference of the average reprojection error from the calibration function and from the "
"reprojected image points is too big (|%g - %g| = %g), testcase %d\n",
rmsErrorFromStereoCalib, rmsErrorFromReprojectedImgPts,
(rmsErrorFromStereoCalib - rmsErrorFromReprojectedImgPts), testcase);
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
/* ----- Compare per view rms re-projection errors ----- */
CV_Assert(rmsErrorPerView1.size() == (size_t)nframes);
CV_Assert(rmsErrorPerViewFromReprojectedImgPts1.size() == (size_t)nframes);
CV_Assert(rmsErrorPerView2.size() == (size_t)nframes);
CV_Assert(rmsErrorPerViewFromReprojectedImgPts2.size() == (size_t)nframes);
int code1 = compare(&rmsErrorPerView1[0], &rmsErrorPerViewFromReprojectedImgPts1[0], nframes,
maxDiffBtwRmsErrors, "per view errors vector");
int code2 = compare(&rmsErrorPerView2[0], &rmsErrorPerViewFromReprojectedImgPts2[0], nframes,
maxDiffBtwRmsErrors, "per view errors vector");
if (code1 < 0)
{
ts->printf(cvtest::TS::LOG,
"Some of the per view rms reprojection errors differ between calibration function and reprojected "
"points, for the first camera, testcase %d\n",
testcase);
ts->set_failed_test_info(code1);
return;
}
if (code2 < 0)
{
ts->printf(cvtest::TS::LOG,
"Some of the per view rms reprojection errors differ between calibration function and reprojected "
"points, for the second camera, testcase %d\n",
testcase);
ts->set_failed_test_info(code2);
return;
}
Mat R1, R2, P1, P2, Q;
Rect roi1, roi2;
rectify(M1, D1, M2, D2, imgsize, R, T, R1, R2, P1, P2, Q, 1, imgsize, &roi1, &roi2, 0);
//check that Q reprojects points before the camera
double testPoint[4] = {0.0, 0.0, 100.0, 1.0};
Mat reprojectedTestPoint = Q * Mat_<double>(4, 1, testPoint);
CV_Assert(reprojectedTestPoint.type() == CV_64FC1);
if( reprojectedTestPoint.at<double>(2) / reprojectedTestPoint.at<double>(3) < 0 )
{
ts->printf( cvtest::TS::LOG, "A point after rectification is reprojected behind the camera, testcase %d\n", testcase);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
}
//check that Q reprojects the same points as reconstructed by triangulation
const float minCoord = -300.0f;
const float maxCoord = 300.0f;
const float minDisparity = 0.1f;
const float maxDisparity = 60.0f;
const int pointsCount = 500;
const float requiredAccuracy = 1e-3f;
const float allowToFail = 0.2f; // 20%
RNG& rng = ts->get_rng();
Mat projectedPoints_1(2, pointsCount, CV_32FC1);
Mat projectedPoints_2(2, pointsCount, CV_32FC1);
Mat disparities(1, pointsCount, CV_32FC1);
rng.fill(projectedPoints_1, RNG::UNIFORM, minCoord, maxCoord);
rng.fill(disparities, RNG::UNIFORM, minDisparity, maxDisparity);
projectedPoints_2.row(0) = projectedPoints_1.row(0) - disparities;
Mat ys_2 = projectedPoints_2.row(1);
projectedPoints_1.row(1).copyTo(ys_2);
Mat points4d;
triangulate(P1, P2, projectedPoints_1, projectedPoints_2, points4d);
Mat homogeneousPoints4d = points4d.t();
const int dimension = 4;
homogeneousPoints4d = homogeneousPoints4d.reshape(dimension);
Mat triangulatedPoints;
convertPointsFromHomogeneous(homogeneousPoints4d, triangulatedPoints);
Mat sparsePoints;
sparsePoints.push_back(projectedPoints_1);
sparsePoints.push_back(disparities);
sparsePoints = sparsePoints.t();
sparsePoints = sparsePoints.reshape(3);
Mat reprojectedPoints;
perspectiveTransform(sparsePoints, reprojectedPoints, Q);
Mat diff;
absdiff(triangulatedPoints, reprojectedPoints, diff);
Mat mask = diff > requiredAccuracy;
mask = mask.reshape(1);
mask = mask.col(0) | mask.col(1) | mask.col(2);
int numFailed = countNonZero(mask);
#if 0
std::cout << "numFailed=" << numFailed << std::endl;
for (int i = 0; i < triangulatedPoints.rows; i++)
{
if (mask.at<uchar>(i))
{
// failed points usually have 'w'~0 (points4d[3])
std::cout << "i=" << i << " triangulatePoints=" << triangulatedPoints.row(i) << " reprojectedPoints=" << reprojectedPoints.row(i) << std::endl <<
" points4d=" << points4d.col(i).t() << " projectedPoints_1=" << projectedPoints_1.col(i).t() << " disparities=" << disparities.col(i).t() << std::endl;
}
}
#endif
if (numFailed >= allowToFail * pointsCount)
{
ts->printf( cvtest::TS::LOG, "Points reprojected with a matrix Q and points reconstructed by triangulation are different (tolerance=%g, failed=%d), testcase %d\n",
requiredAccuracy, numFailed, testcase);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
}
//check correctMatches
const float constraintAccuracy = 1e-5f;
Mat newPoints1, newPoints2;
Mat points1 = projectedPoints_1.t();
points1 = points1.reshape(2, 1);
Mat points2 = projectedPoints_2.t();
points2 = points2.reshape(2, 1);
correctMatches(F, points1, points2, newPoints1, newPoints2);
Mat newHomogeneousPoints1, newHomogeneousPoints2;
convertPointsToHomogeneous(newPoints1, newHomogeneousPoints1);
convertPointsToHomogeneous(newPoints2, newHomogeneousPoints2);
newHomogeneousPoints1 = newHomogeneousPoints1.reshape(1);
newHomogeneousPoints2 = newHomogeneousPoints2.reshape(1);
Mat typedF;
F.convertTo(typedF, newHomogeneousPoints1.type());
for (int i = 0; i < newHomogeneousPoints1.rows; ++i)
{
Mat error = newHomogeneousPoints2.row(i) * typedF * newHomogeneousPoints1.row(i).t();
CV_Assert(error.rows == 1 && error.cols == 1);
if (cvtest::norm(error, NORM_L2) > constraintAccuracy)
{
ts->printf( cvtest::TS::LOG, "Epipolar constraint is violated after correctMatches, testcase %d\n", testcase);
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
}
}
// rectifyUncalibrated
CV_Assert( imgpt1.size() == imgpt2.size() );
Mat _imgpt1( total, 1, CV_32FC2 ), _imgpt2( total, 1, CV_32FC2 );
vector<vector<Point2f> >::const_iterator iit1 = imgpt1.begin();
vector<vector<Point2f> >::const_iterator iit2 = imgpt2.begin();
for( int pi = 0; iit1 != imgpt1.end(); ++iit1, ++iit2 )
{
vector<Point2f>::const_iterator pit1 = iit1->begin();
vector<Point2f>::const_iterator pit2 = iit2->begin();
CV_Assert( iit1->size() == iit2->size() );
for( ; pit1 != iit1->end(); ++pit1, ++pit2, pi++ )
{
_imgpt1.at<Point2f>(pi,0) = Point2f( pit1->x, pit1->y );
_imgpt2.at<Point2f>(pi,0) = Point2f( pit2->x, pit2->y );
}
}
Mat _M1, _M2, _D1, _D2;
vector<Mat> _R1, _R2, _T1, _T2;
calibrateCamera( objpt, imgpt1, imgsize, _M1, _D1, _R1, _T1, 0 );
calibrateCamera( objpt, imgpt2, imgsize, _M2, _D2, _R2, _T2, 0 );
undistortPoints( _imgpt1, _imgpt1, _M1, _D1, Mat(), _M1 );
undistortPoints( _imgpt2, _imgpt2, _M2, _D2, Mat(), _M2 );
Mat matF, _H1, _H2;
matF = findFundamentalMat( _imgpt1, _imgpt2 );
rectifyUncalibrated( _imgpt1, _imgpt2, matF, imgsize, _H1, _H2 );
Mat rectifPoints1, rectifPoints2;
perspectiveTransform( _imgpt1, rectifPoints1, _H1 );
perspectiveTransform( _imgpt2, rectifPoints2, _H2 );
bool verticalStereo = abs(P2.at<double>(0,3)) < abs(P2.at<double>(1,3));
double maxDiff_c = 0, maxDiff_uc = 0;
for( int i = 0, k = 0; i < nframes; i++ )
{
vector<Point2f> temp[2];
undistortPoints(imgpt1[i], temp[0], M1, D1, R1, P1);
undistortPoints(imgpt2[i], temp[1], M2, D2, R2, P2);
for( int j = 0; j < npoints; j++, k++ )
{
double diff_c = verticalStereo ? abs(temp[0][j].x - temp[1][j].x) : abs(temp[0][j].y - temp[1][j].y);
Point2f d = rectifPoints1.at<Point2f>(k,0) - rectifPoints2.at<Point2f>(k,0);
double diff_uc = verticalStereo ? abs(d.x) : abs(d.y);
maxDiff_c = max(maxDiff_c, diff_c);
maxDiff_uc = max(maxDiff_uc, diff_uc);
if( maxDiff_c > maxScanlineDistErr_c )
{
ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used calibrated stereo), testcase %d\n",
verticalStereo ? "x" : "y", diff_c, testcase);
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
return;
}
if( maxDiff_uc > maxScanlineDistErr_uc )
{
ts->printf( cvtest::TS::LOG, "The distance between %s coordinates is too big(=%g) (used uncalibrated stereo), testcase %d\n",
verticalStereo ? "x" : "y", diff_uc, testcase);
ts->set_failed_test_info( cvtest::TS::FAIL_BAD_ACCURACY );
return;
}
}
}
ts->printf( cvtest::TS::LOG, "Testcase %d. Max distance (calibrated) =%g\n"
"Max distance (uncalibrated) =%g\n", testcase, maxDiff_c, maxDiff_uc );
}
}
//-------------------------------- CV_StereoCalibrationTest_CPP ------------------------------
class CV_StereoCalibrationTest_CPP : public CV_StereoCalibrationTest
{
public:
CV_StereoCalibrationTest_CPP() {}
protected:
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags );
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
Size imageSize, const Mat& R, const Mat& T,
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
double alpha, Size newImageSize,
Rect* validPixROI1, Rect* validPixROI2, int flags );
virtual bool rectifyUncalibrated( const Mat& points1,
const Mat& points2, const Mat& F, Size imgSize,
Mat& H1, Mat& H2, double threshold=5 );
virtual void triangulate( const Mat& P1, const Mat& P2,
const Mat &points1, const Mat &points2,
Mat &points4D );
virtual void correct( const Mat& F,
const Mat &points1, const Mat &points2,
Mat &newPoints1, Mat &newPoints2 );
};
double CV_StereoCalibrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags )
{
vector<Mat> rvecs, tvecs;
Mat perViewErrorsMat;
double avgErr = stereoCalibrate( objectPoints, imagePoints1, imagePoints2,
cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
imageSize, R, T, E, F,
rvecs, tvecs, perViewErrorsMat,
flags, criteria );
size_t numImgs = imagePoints1.size();
if (perViewErrors1.size() != numImgs)
{
perViewErrors1.resize(numImgs);
}
if (perViewErrors2.size() != numImgs)
{
perViewErrors2.resize(numImgs);
}
for (int i = 0; i < (int)numImgs; i++)
{
perViewErrors1[i] = perViewErrorsMat.at<double>(i, 0);
perViewErrors2[i] = perViewErrorsMat.at<double>(i, 1);
}
if (rotationMatrices.size() != numImgs)
{
rotationMatrices.resize(numImgs);
}
if (translationVectors.size() != numImgs)
{
translationVectors.resize(numImgs);
}
for( size_t i = 0; i < numImgs; i++ )
{
Mat r9;
cv::Rodrigues( rvecs[i], r9 );
r9.convertTo(rotationMatrices[i], CV_64F);
tvecs[i].convertTo(translationVectors[i], CV_64F);
}
return avgErr;
}
void CV_StereoCalibrationTest_CPP::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
Size imageSize, const Mat& R, const Mat& T,
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
double alpha, Size newImageSize,
Rect* validPixROI1, Rect* validPixROI2, int flags )
{
stereoRectify( cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
imageSize, R, T, R1, R2, P1, P2, Q, flags, alpha, newImageSize, validPixROI1, validPixROI2 );
}
bool CV_StereoCalibrationTest_CPP::rectifyUncalibrated( const Mat& points1,
const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
{
return stereoRectifyUncalibrated( points1, points2, F, imgSize, H1, H2, threshold );
}
void CV_StereoCalibrationTest_CPP::triangulate( const Mat& P1, const Mat& P2,
const Mat &points1, const Mat &points2,
Mat &points4D )
{
triangulatePoints(P1, P2, points1, points2, points4D);
}
void CV_StereoCalibrationTest_CPP::correct( const Mat& F,
const Mat &points1, const Mat &points2,
Mat &newPoints1, Mat &newPoints2 )
{
correctMatches(F, points1, points2, newPoints1, newPoints2);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////// Register Cameras ////////////////////////////////////////////////
class CV_CameraRegistrationTest : public cvtest::BaseTest
{
public:
CV_CameraRegistrationTest();
~CV_CameraRegistrationTest();
void clear();
protected:
// covers of tested functions
virtual double registerCameraPair( const vector<vector<Point3f> >& objectPoints1,
const vector<vector<Point3f> >& objectPoints2,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1, CameraModel cameraModel1,
Mat& cameraMatrix2, Mat& distCoeffs2, CameraModel cameraModel2,
Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags ) = 0;
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags ) = 0;
int compare(double* val, double* refVal, int len,
double eps, const char* paramName);
void run(int);
};
CV_CameraRegistrationTest::CV_CameraRegistrationTest()
{
}
CV_CameraRegistrationTest::~CV_CameraRegistrationTest()
{
clear();
}
void CV_CameraRegistrationTest::clear()
{
cvtest::BaseTest::clear();
}
int CV_CameraRegistrationTest::compare(double* val, double* ref_val, int len,
double eps, const char* param_name )
{
return cvtest::cmpEps2_64f( ts, val, ref_val, len, eps, param_name );
}
void CV_CameraRegistrationTest::run( int )
{
const int ntests = 1;
const double maxReprojErr = 2;
const double maxDiffBtwRmsErrors = 1e-4;
const double maxDiffBtwEstErrors = 1e-10;
FILE* f = 0;
for(int testcase = 1; testcase <= ntests; testcase++)
{
cv::String filepath;
char buf[1000];
filepath = cv::format("%scv/stereo/case%d/stereo_calib.txt", ts->get_data_path().c_str(), testcase );
f = fopen(filepath.c_str(), "rt");
Size patternSize;
vector<string> imglist;
if( !f || !fgets(buf, sizeof(buf)-3, f) || sscanf(buf, "%d%d", &patternSize.width, &patternSize.height) != 2 )
{
ts->printf( cvtest::TS::LOG, "The file %s can not be opened or has invalid content\n", filepath.c_str() );
ts->set_failed_test_info( f ? cvtest::TS::FAIL_INVALID_TEST_DATA : cvtest::TS::FAIL_MISSING_TEST_DATA );
if (f)
fclose(f);
return;
}
for(;;)
{
if( !fgets( buf, sizeof(buf)-3, f ))
break;
size_t len = strlen(buf);
while( len > 0 && isspace(buf[len-1]))
buf[--len] = '\0';
if( buf[0] == '#')
continue;
filepath = cv::format("%scv/stereo/case%d/%s", ts->get_data_path().c_str(), testcase, buf );
imglist.push_back(string(filepath));
}
fclose(f);
if( imglist.size() == 0 || imglist.size() % 2 != 0 )
{
ts->printf( cvtest::TS::LOG, "The number of images is 0 or an odd number in the case #%d\n", testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_TEST_DATA );
return;
}
int nframes = (int)(imglist.size()/2);
int npoints = patternSize.width*patternSize.height;
vector<vector<Point3f> > objpt(nframes);
vector<vector<Point2f> > imgpt1(nframes);
vector<vector<Point2f> > imgpt2(nframes);
Size imgsize;
for( int i = 0; i < nframes; i++ )
{
Mat left = imread(imglist[i*2]);
Mat right = imread(imglist[i*2+1]);
if(left.empty() || right.empty())
{
ts->printf( cvtest::TS::LOG, "Can not load images %s and %s, testcase %d\n",
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
return;
}
imgsize = left.size();
bool found1 = findChessboardCorners(left, patternSize, imgpt1[i]);
bool found2 = findChessboardCorners(right, patternSize, imgpt2[i]);
if(!found1 || !found2)
{
ts->printf( cvtest::TS::LOG, "The function could not detect boards (%d x %d) on the images %s and %s, testcase %d\n",
patternSize.width, patternSize.height,
imglist[i*2].c_str(), imglist[i*2+1].c_str(), testcase );
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
for( int j = 0; j < npoints; j++ )
objpt[i].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
}
vector<RotMat> rotMats1(nframes);
vector<Vec3d> transVecs1(nframes);
vector<RotMat> rotMats2(nframes);
vector<Vec3d> transVecs2(nframes);
vector<double> rmsErrorPerView1(nframes);
vector<double> rmsErrorPerView2(nframes);
vector<double> rmsErrorPerViewFromReprojectedImgPts1(nframes);
vector<double> rmsErrorPerViewFromReprojectedImgPts2(nframes);
Mat M1 = Mat::eye(3,3,CV_64F), M2 = Mat::eye(3,3,CV_64F), D1(5,1,CV_64F), D2(5,1,CV_64F);
Mat R_stereo, T_stereo, R_register, T_register;
Mat E_stereo, F_stereo, E_register, F_register;
M1.at<double>(0,2) = M2.at<double>(0,2)=(imgsize.width-1)*0.5;
M1.at<double>(1,2) = M2.at<double>(1,2)=(imgsize.height-1)*0.5;
D1 = Scalar::all(0);
D2 = Scalar::all(0
);
// Initialize the intrinsics
calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R_stereo, T_stereo, E_stereo, F_stereo,
rotMats1, transVecs1, rmsErrorPerView1, rmsErrorPerView2,
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
CALIB_SAME_FOCAL_LENGTH
//+ CV_CALIB_FIX_ASPECT_RATIO
+ CALIB_FIX_PRINCIPAL_POINT
+ CALIB_ZERO_TANGENT_DIST
+ CALIB_FIX_K3
+ CALIB_FIX_K4 + CALIB_FIX_K5 //+ CV_CALIB_FIX_K6
);
// Use the fixed intrinsics to esimtate with two different methods
double rmsErrorFromStereoCalibStereo = calibrateStereoCamera(objpt, imgpt1, imgpt2, M1, D1, M2, D2, imgsize, R_stereo, T_stereo, E_stereo, F_stereo,
rotMats1, transVecs1, rmsErrorPerView1, rmsErrorPerView2,
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
CALIB_FIX_INTRINSIC
);
double rmsErrorFromStereoCalibRegister = registerCameraPair(objpt, objpt, imgpt1, imgpt2, M1, D1, CALIB_MODEL_PINHOLE, M2, D2, CALIB_MODEL_PINHOLE, R_register, T_register, E_register, F_register,
rotMats2, transVecs2, rmsErrorPerView1, rmsErrorPerView2,
TermCriteria(TermCriteria::MAX_ITER+TermCriteria::EPS, 30, 1e-6),
0
);
/* rmsErrorFromStereoCalibRegister /= nframes*npoints; */
if (rmsErrorFromStereoCalibRegister > maxReprojErr)
{
ts->printf(cvtest::TS::LOG, "The average reprojection error is too big (=%g), testcase %d\n",
rmsErrorFromStereoCalibRegister, testcase);
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
double rmsErrorFromReprojectedImgPts = 0.0f;
if (rotMats1.empty() || transVecs1.empty())
{
rmsErrorPerViewFromReprojectedImgPts1 = rmsErrorPerView1;
rmsErrorPerViewFromReprojectedImgPts2 = rmsErrorPerView2;
rmsErrorFromReprojectedImgPts = rmsErrorFromStereoCalibRegister;
}
else
{
size_t totalPoints = 0;
double totalErr[2] = { 0, 0 };
for (size_t i = 0; i < objpt.size(); ++i) {
RotMat r1 = rotMats1[i];
Vec3d t1 = transVecs1[i];
RotMat r2 = Mat(R_register * r1);
Mat T2t = R_register * t1;
Vec3d t2 = Mat(T2t + T_register);
vector<Point2f> reprojectedImgPts[2] = { vector<Point2f>(nframes),
vector<Point2f>(nframes) };
projectPoints(objpt[i], r1, t1, M1, D1, reprojectedImgPts[0]);
projectPoints(objpt[i], r2, t2, M2, D2, reprojectedImgPts[1]);
double viewErr[2];
viewErr[0] = cv::norm(imgpt1[i], reprojectedImgPts[0], cv::NORM_L2SQR);
viewErr[1] = cv::norm(imgpt2[i], reprojectedImgPts[1], cv::NORM_L2SQR);
size_t n = objpt[i].size();
totalErr[0] += viewErr[0];
totalErr[1] += viewErr[1];
totalPoints += n;
rmsErrorPerViewFromReprojectedImgPts1[i] = sqrt(viewErr[0] / n);
rmsErrorPerViewFromReprojectedImgPts2[i] = sqrt(viewErr[1] / n);
}
rmsErrorFromReprojectedImgPts = std::sqrt((totalErr[0] + totalErr[1]) / (2 * totalPoints));
}
if (abs(rmsErrorFromStereoCalibRegister - rmsErrorFromReprojectedImgPts) > maxDiffBtwRmsErrors)
{
ts->printf(cvtest::TS::LOG,
"The difference of the average reprojection error from the calibration function and from the "
"reprojected image points is too big (|%g - %g| = %g), testcase %d\n",
rmsErrorFromStereoCalibRegister, rmsErrorFromReprojectedImgPts,
(rmsErrorFromStereoCalibRegister - rmsErrorFromReprojectedImgPts), testcase);
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
/* ----- Compare per view rms re-projection errors ----- */
CV_Assert(rmsErrorPerView1.size() == (size_t)nframes);
CV_Assert(rmsErrorPerViewFromReprojectedImgPts1.size() == (size_t)nframes);
CV_Assert(rmsErrorPerView2.size() == (size_t)nframes);
CV_Assert(rmsErrorPerViewFromReprojectedImgPts2.size() == (size_t)nframes);
int code1 = compare(&rmsErrorPerView1[0], &rmsErrorPerViewFromReprojectedImgPts1[0], nframes,
maxDiffBtwRmsErrors, "per view errors vector");
int code2 = compare(&rmsErrorPerView2[0], &rmsErrorPerViewFromReprojectedImgPts2[0], nframes,
maxDiffBtwRmsErrors, "per view errors vector");
if (code1 < 0)
{
ts->printf(cvtest::TS::LOG,
"Some of the per view rms reprojection errors differ between calibration function and reprojected "
"points, for the first camera, testcase %d\n",
testcase);
ts->set_failed_test_info(code1);
return;
}
if (code2 < 0)
{
ts->printf(cvtest::TS::LOG,
"Some of the per view rms reprojection errors differ between calibration function and reprojected "
"points, for the second camera, testcase %d\n",
testcase);
ts->set_failed_test_info(code2);
return;
}
/* ----- compare the result from stereoCalibrate and registerCameras ----- */
if (abs(rmsErrorFromStereoCalibStereo - rmsErrorFromStereoCalibRegister) > maxDiffBtwRmsErrors)
{
ts->printf(cvtest::TS::LOG,
"The difference of the average reprojection error from the register camera and stero calibration is too large (|%g - %g| = %g), testcase %d\n",
rmsErrorFromStereoCalibStereo, rmsErrorFromStereoCalibRegister,
(rmsErrorFromStereoCalibStereo - rmsErrorFromStereoCalibRegister), testcase);
ts->set_failed_test_info(cvtest::TS::FAIL_INVALID_OUTPUT);
return;
}
int code3 = compare(&R_stereo.at<double>(0), &R_register.at<double>(0), 9, maxDiffBtwEstErrors, "R vector");
int code4 = compare(&T_stereo.at<double>(0), &T_register.at<double>(0), 3, maxDiffBtwEstErrors, "T vector");
int code5 = compare(&E_stereo.at<double>(0), &E_register.at<double>(0), 9, maxDiffBtwEstErrors, "E vector");
int code6 = compare(&F_stereo.at<double>(0), &F_register.at<double>(0), 9, maxDiffBtwEstErrors, "F vector");
if (code3 < 0)
{
ts->printf(cvtest::TS::LOG,
"The estimated R does not match, testcase %d\n",
testcase);
ts->set_failed_test_info(code3);
return;
}
if (code4 < 0)
{
ts->printf(cvtest::TS::LOG,
"The estimated T does not match, testcase %d\n",
testcase);
ts->set_failed_test_info(code4);
return;
}
if (code5 < 0)
{
ts->printf(cvtest::TS::LOG,
"The estimated E does not match, testcase %d\n",
testcase);
ts->set_failed_test_info(code5);
return;
}
if (code6 < 0)
{
ts->printf(cvtest::TS::LOG,
"The estimated F does not match, testcase %d\n",
testcase);
ts->set_failed_test_info(code6);
return;
}
}
}
//-------------------------------- CV_CameraRegistrationTest_CPP ------------------------------
class CV_CameraRegistrationTest_CPP : public CV_CameraRegistrationTest
{
public:
CV_CameraRegistrationTest_CPP() {}
protected:
virtual double registerCameraPair( const vector<vector<Point3f> >& objectPoints1,
const vector<vector<Point3f> >& objectPoints2,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1, CameraModel cameraModel1,
Mat& cameraMatrix2, Mat& distCoeffs2, CameraModel cameraModel2,
Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags );
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags );
};
double CV_CameraRegistrationTest_CPP::registerCameraPair( const vector<vector<Point3f> >& objectPoints1,
const vector<vector<Point3f> >& objectPoints2,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1, CameraModel cameraModel1,
Mat& cameraMatrix2, Mat& distCoeffs2, CameraModel cameraModel2,
Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags )
{
vector<Mat> rvecs, tvecs;
Mat perViewErrorsMat;
double avgErr = registerCameras(objectPoints1, objectPoints2, imagePoints1, imagePoints2,
cameraMatrix1, distCoeffs1, cameraModel1,
cameraMatrix2, distCoeffs2, cameraModel2,
R, T, E, F,
rvecs, tvecs, perViewErrorsMat,
flags, criteria);
size_t numImgs = imagePoints1.size();
if (perViewErrors1.size() != numImgs)
{
perViewErrors1.resize(numImgs);
}
if (perViewErrors2.size() != numImgs)
{
perViewErrors2.resize(numImgs);
}
for (int i = 0; i < (int)numImgs; i++)
{
perViewErrors1[i] = perViewErrorsMat.at<double>(i, 0);
perViewErrors2[i] = perViewErrorsMat.at<double>(i, 1);
}
if (rotationMatrices.size() != numImgs)
{
rotationMatrices.resize(numImgs);
}
if (translationVectors.size() != numImgs)
{
translationVectors.resize(numImgs);
}
for( size_t i = 0; i < numImgs; i++ )
{
Mat r9;
cv::Rodrigues( rvecs[i], r9 );
r9.convertTo(rotationMatrices[i], CV_64F);
tvecs[i].convertTo(translationVectors[i], CV_64F);
}
return avgErr;
}
double CV_CameraRegistrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags )
{
vector<Mat> rvecs, tvecs;
Mat perViewErrorsMat;
double avgErr = stereoCalibrate( objectPoints, imagePoints1, imagePoints2,
cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
imageSize, R, T, E, F,
rvecs, tvecs, perViewErrorsMat,
flags, criteria );
size_t numImgs = imagePoints1.size();
if (perViewErrors1.size() != numImgs)
{
perViewErrors1.resize(numImgs);
}
if (perViewErrors2.size() != numImgs)
{
perViewErrors2.resize(numImgs);
}
for (int i = 0; i < (int)numImgs; i++)
{
perViewErrors1[i] = perViewErrorsMat.at<double>(i, 0);
perViewErrors2[i] = perViewErrorsMat.at<double>(i, 1);
}
if (rotationMatrices.size() != numImgs)
{
rotationMatrices.resize(numImgs);
}
if (translationVectors.size() != numImgs)
{
translationVectors.resize(numImgs);
}
for( size_t i = 0; i < numImgs; i++ )
{
Mat r9;
cv::Rodrigues( rvecs[i], r9 );
r9.convertTo(rotationMatrices[i], CV_64F);
tvecs[i].convertTo(translationVectors[i], CV_64F);
}
return avgErr;
}
TEST(Calib3d_CameraRegistration_CPP, regression) { CV_CameraRegistrationTest_CPP test; test.safe_run(); }
TEST(Calib3d_CalibrateCamera_CPP, regression) { CV_CameraCalibrationTest_CPP test; test.safe_run(); }
TEST(Calib3d_StereoCalibrate_CPP, regression) { CV_StereoCalibrationTest_CPP test; test.safe_run(); }
//-------------------------------- CV_MultiviewCalibrationTest_CPP ------------------------------
class CV_MultiviewCalibrationTest_CPP : public CV_StereoCalibrationTest
{
public:
CV_MultiviewCalibrationTest_CPP() {}
protected:
virtual double calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria criteria, int flags );
virtual void rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
Size imageSize, const Mat& R, const Mat& T,
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
double alpha, Size newImageSize,
Rect* validPixROI1, Rect* validPixROI2, int flags );
virtual bool rectifyUncalibrated( const Mat& points1,
const Mat& points2, const Mat& F, Size imgSize,
Mat& H1, Mat& H2, double threshold=5 );
virtual void triangulate( const Mat& P1, const Mat& P2,
const Mat &points1, const Mat &points2,
Mat &points4D );
virtual void correct( const Mat& F,
const Mat &points1, const Mat &points2,
Mat &newPoints1, Mat &newPoints2 );
};
double CV_MultiviewCalibrationTest_CPP::calibrateStereoCamera( const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints1,
const vector<vector<Point2f> >& imagePoints2,
Mat& cameraMatrix1, Mat& distCoeffs1,
Mat& cameraMatrix2, Mat& distCoeffs2,
Size imageSize, Mat& R, Mat& T,
Mat& E, Mat& F,
std::vector<RotMat>& rotationMatrices, std::vector<Vec3d>& translationVectors,
vector<double>& perViewErrors1, vector<double>& perViewErrors2,
TermCriteria /*criteria*/, int flags )
{
std::vector<cv::Mat> rvecs, tvecs;
std::vector<cv::Mat> Ks, distortions, Rs, Ts;
cv::Mat errors_mat, output_pairs, rvecs0, tvecs0;
int numImgs = (int)objectPoints.size();
std::vector<std::vector<cv::Mat>> image_points_all(2, std::vector<Mat>(numImgs));
for (int i = 0; i < numImgs; i++)
{
Mat img_pts1 = Mat(imagePoints1[i], false);
Mat img_pts2 = Mat(imagePoints2[i], false);
img_pts1.copyTo(image_points_all[0][i]);
img_pts2.copyTo(image_points_all[1][i]);
}
std::vector<Size> image_sizes (2, imageSize);
Mat visibility_mat = Mat_<uchar>::ones(2, numImgs);
std::vector<uchar> models(2, cv::CALIB_MODEL_PINHOLE);
std::vector<int> all_flags(2, flags);
double rms = calibrateMultiview(objectPoints, image_points_all, image_sizes, visibility_mat, models,
Ks, distortions, Rs, Ts, /*pairs*/ noArray(), rvecs, tvecs, errors_mat, all_flags);
if (perViewErrors1.size() != (size_t)numImgs)
{
perViewErrors1.resize(numImgs);
}
if (perViewErrors2.size() != (size_t)numImgs)
{
perViewErrors2.resize(numImgs);
}
for (int i = 0; i < numImgs; i++)
{
perViewErrors1[i] = errors_mat.at<double>(0, i);
perViewErrors2[i] = errors_mat.at<double>(1, i);
}
if (rotationMatrices.size() != (size_t)numImgs)
{
rotationMatrices.resize(numImgs);
}
if (translationVectors.size() != (size_t)numImgs)
{
translationVectors.resize(numImgs);
}
for( int i = 0; i < numImgs; i++ )
{
Mat r9;
cv::Rodrigues( rvecs[i], r9 );
r9.convertTo(rotationMatrices[i], CV_64F);
tvecs[i].convertTo(translationVectors[i], CV_64F);
}
cv::Rodrigues(Rs[1], R);
Ts[1].copyTo(T);
distortions[0].copyTo(distCoeffs1);
distortions[1].copyTo(distCoeffs2);
Ks[0].copyTo(cameraMatrix1);
Ks[1].copyTo(cameraMatrix2);
Matx33d skewT( 0, -T.at<double>(2), T.at<double>(1),
T.at<double>(2), 0, -T.at<double>(0),
-T.at<double>(1), T.at<double>(0), 0);
E = Mat(skewT * R);
F = Ks[1].inv().t() * E * Ks[0].inv();
return rms;
}
void CV_MultiviewCalibrationTest_CPP::rectify( const Mat& cameraMatrix1, const Mat& distCoeffs1,
const Mat& cameraMatrix2, const Mat& distCoeffs2,
Size imageSize, const Mat& R, const Mat& T,
Mat& R1, Mat& R2, Mat& P1, Mat& P2, Mat& Q,
double alpha, Size newImageSize,
Rect* validPixROI1, Rect* validPixROI2, int flags )
{
stereoRectify( cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2,
imageSize, R, T, R1, R2, P1, P2, Q, flags, alpha, newImageSize,validPixROI1, validPixROI2 );
}
bool CV_MultiviewCalibrationTest_CPP::rectifyUncalibrated( const Mat& points1,
const Mat& points2, const Mat& F, Size imgSize, Mat& H1, Mat& H2, double threshold )
{
return stereoRectifyUncalibrated( points1, points2, F, imgSize, H1, H2, threshold );
}
void CV_MultiviewCalibrationTest_CPP::triangulate( const Mat& P1, const Mat& P2,
const Mat &points1, const Mat &points2,
Mat &points4D )
{
triangulatePoints(P1, P2, points1, points2, points4D);
}
void CV_MultiviewCalibrationTest_CPP::correct( const Mat& F,
const Mat &points1, const Mat &points2,
Mat &newPoints1, Mat &newPoints2 )
{
correctMatches(F, points1, points2, newPoints1, newPoints2);
}
TEST(Calib3d_MultiviewCalibrate_CPP, regression) { CV_MultiviewCalibrationTest_CPP test; test.safe_run(); }
///////////////////////////////////////////////////////////////////////////////////////////////////
TEST(Calib3d_StereoCalibrate_CPP, extended)
{
cvtest::TS* ts = cvtest::TS::ptr();
String filepath = cv::format("%scv/stereo/case%d/", ts->get_data_path().c_str(), 1 );
Mat left = imread(filepath+"left01.png");
Mat right = imread(filepath+"right01.png");
if(left.empty() || right.empty())
{
ts->set_failed_test_info( cvtest::TS::FAIL_MISSING_TEST_DATA );
return;
}
vector<vector<Point2f> > imgpt1(1), imgpt2(1);
vector<vector<Point3f> > objpt(1);
Size patternSize(9, 6), imageSize(640, 480);
bool found1 = findChessboardCorners(left, patternSize, imgpt1[0]);
bool found2 = findChessboardCorners(right, patternSize, imgpt2[0]);
if(!found1 || !found2)
{
ts->set_failed_test_info( cvtest::TS::FAIL_INVALID_OUTPUT );
return;
}
for( int j = 0; j < patternSize.width*patternSize.height; j++ )
objpt[0].push_back(Point3f((float)(j%patternSize.width), (float)(j/patternSize.width), 0.f));
Mat K1, K2, c1, c2, R, T, E, F, err;
int flags = 0;
double res0 = stereoCalibrate( objpt, imgpt1, imgpt2,
K1, c1, K2, c2,
imageSize, R, T, E, F, err, flags);
flags = CALIB_USE_EXTRINSIC_GUESS;
double res1 = stereoCalibrate( objpt, imgpt1, imgpt2,
K1, c1, K2, c2,
imageSize, R, T, E, F, err, flags);
EXPECT_LE(res1, res0);
EXPECT_TRUE(err.total() == 2);
}
TEST(Calib_StereoCalibrate, regression_22421)
{
cv::Mat K1, K2, dist1, dist2;
std::vector<Mat> image_points1, image_points2;
Mat desiredR, desiredT;
std::string fname = cvtest::TS::ptr()->get_data_path() + std::string("/cv/cameracalibration/regression22421.yaml.gz");
FileStorage fs(fname, FileStorage::Mode::READ);
ASSERT_TRUE(fs.isOpened());
fs["imagePoints1"] >> image_points1;
fs["imagePoints2"] >> image_points2;
fs["K1"] >> K1;
fs["K2"] >> K2;
fs["dist1"] >> dist1;
fs["dist2"] >> dist2;
fs["desiredR"] >> desiredR;
fs["desiredT"] >> desiredT;
std::vector<float> obj_points = {0, 0, 0,
0.5f, 0, 0,
1.f, 0, 0,
1.5000001f, 0, 0,
2.0f, 0, 0,
0, 0.5f, 0,
0.5f, 0.5f, 0,
1.f, 0.5, 0,
1.5000001f, 0.5f, 0,
2.f, 0.5f, 0,
0, 1.f, 0,
0.5f, 1.f, 0,
1.f, 1.f, 0,
1.5000001f, 1.f, 0,
2.f, 1.f, 0,
0, 1.5000001f, 0,
0.5f, 1.5000001f, 0,
1.f, 1.5000001f, 0,
1.5000001f, 1.5000001f, 0,
2.f, 1.5000001f, 0};
cv::Mat obj_points_mat(obj_points, true);
obj_points_mat = obj_points_mat.reshape(1, int(obj_points.size()) / 3);
std::vector<cv::Mat> grid_points(image_points1.size(), obj_points_mat);
cv::Mat R, T;
double error = cv::stereoCalibrate(grid_points, image_points1, image_points2,
K1, dist1, K2, dist2, cv::Size(), R, T,
cv::noArray(), cv::noArray(), cv::noArray(), cv::CALIB_FIX_INTRINSIC);
EXPECT_LE(error, 0.071544);
double rerr = cv::norm(R, desiredR, NORM_INF);
double terr = cv::norm(T, desiredT, NORM_INF);
EXPECT_LE(rerr, 0.0000001);
EXPECT_LE(terr, 0.0000001);
}
}} // namespace