mirror of
https://github.com/opencv/opencv.git
synced 2026-11-09 18:04:29 -06:00
Merge pull request #30176 from SavyaSanchi-Sharma:callibrateCam
calib: accept float64 points in calibrateCamera - #30176 Lets calibrateCamera, calibrateCameraRO, stereoCalibrate, initCameraMatrix2D, and registerCameras accept Point3d/Point2d (double) input in addition to Point3f/Point2f. Adds a new test suite (float64Points) exercising each of those entry points with double-precision input and comparing accuracy against the float32 path. ### 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
This commit is contained in:
committed by
GitHub
parent
731831782c
commit
1e21d6ed7d
@@ -564,7 +564,8 @@ CV_EXPORTS_W Mat initCameraMatrix2D( InputArrayOfArrays objectPoints,
|
||||
pattern.
|
||||
|
||||
@param objectPoints In the new interface it is a vector of vectors of calibration pattern points in
|
||||
the calibration pattern coordinate space (e.g. std::vector<std::vector<cv::Vec3f>>). The outer
|
||||
the calibration pattern coordinate space (e.g. std::vector<std::vector<cv::Vec3f>> or
|
||||
std::vector<std::vector<cv::Vec3d>>). Both single and double precision points are accepted. The outer
|
||||
vector contains as many elements as the number of pattern views. If the same calibration pattern
|
||||
is shown in each view and it is fully visible, all the vectors will be the same. Although, it is
|
||||
possible to use partially occluded patterns or even different patterns in different views. Then,
|
||||
@@ -573,7 +574,8 @@ XY coordinate plane (thus 0 in the Z-coordinate), if the used calibration patter
|
||||
In the old interface all the vectors of object points from different views are concatenated
|
||||
together.
|
||||
@param imagePoints In the new interface it is a vector of vectors of the projections of calibration
|
||||
pattern points (e.g. std::vector<std::vector<cv::Vec2f>>). imagePoints.size() and
|
||||
pattern points (e.g. std::vector<std::vector<cv::Vec2f>> or std::vector<std::vector<cv::Vec2d>>).
|
||||
Both single and double precision points are accepted. imagePoints.size() and
|
||||
objectPoints.size(), and imagePoints[i].size() and objectPoints[i].size() for each i, must be equal,
|
||||
respectively. In the old interface all the vectors of object points from different views are
|
||||
concatenated together.
|
||||
@@ -745,7 +747,8 @@ for details.
|
||||
@param newObjPoints The updated output vector of calibration pattern points. The coordinates might
|
||||
be scaled based on three fixed points. The returned coordinates are accurate only if the above
|
||||
mentioned three fixed points are accurate. If not needed, noArray() can be passed in. This parameter
|
||||
is ignored with standard calibration method.
|
||||
is ignored with standard calibration method. The output has the same depth as objectPoints[0]
|
||||
(CV_32F or CV_64F).
|
||||
@param stdDeviationsIntrinsics Output vector of standard deviations estimated for intrinsic parameters.
|
||||
See #calibrateCamera for details.
|
||||
@param stdDeviationsExtrinsics Output vector of standard deviations estimated for extrinsic parameters.
|
||||
|
||||
@@ -2741,65 +2741,60 @@ static void collectCalibrationData( InputArrayOfArrays objectPoints,
|
||||
Mat objectPoint = objectPoints.getMat(i);
|
||||
if (objectPoint.empty())
|
||||
CV_Error(cv::Error::StsBadSize, "objectPoints should not contain empty vector of vectors of points");
|
||||
int numberOfObjectPoints = objectPoint.checkVector(3, CV_32F, false);
|
||||
int numberOfObjectPoints = std::max(objectPoint.checkVector(3, CV_32F, false), objectPoint.checkVector(3, CV_64F, false));
|
||||
if (numberOfObjectPoints <= 0)
|
||||
CV_Error(cv::Error::StsUnsupportedFormat, "objectPoints should contain vector of vectors of points of type Point3f");
|
||||
CV_Error(cv::Error::StsUnsupportedFormat, "objectPoints should contain vector of vectors of points of type Point3f or Point3d");
|
||||
|
||||
Mat imagePoint1 = imagePoints1.getMat(i);
|
||||
if (imagePoint1.empty())
|
||||
CV_Error(cv::Error::StsBadSize, "imagePoints1 should not contain empty vector of vectors of points");
|
||||
int numberOfImagePoints = imagePoint1.checkVector(2, CV_32F, false);
|
||||
int numberOfImagePoints = std::max(imagePoint1.checkVector(2, CV_32F, false), imagePoint1.checkVector(2, CV_64F, false));
|
||||
if (numberOfImagePoints <= 0)
|
||||
CV_Error(cv::Error::StsUnsupportedFormat, "imagePoints1 should contain vector of vectors of points of type Point2f");
|
||||
CV_Error(cv::Error::StsUnsupportedFormat, "imagePoints1 should contain vector of vectors of points of type Point2f or Point2d");
|
||||
CV_CheckEQ(numberOfObjectPoints, numberOfImagePoints, "Number of object and image points must be equal");
|
||||
|
||||
total += numberOfObjectPoints;
|
||||
}
|
||||
|
||||
npoints.create(1, (int)nimages, CV_32S);
|
||||
objPt.create(1, (int)total, CV_32FC3);
|
||||
imgPt1.create(1, (int)total, CV_32FC2);
|
||||
Point2f* imgPtData2 = 0;
|
||||
objPt.create(1, (int)total, CV_64FC3);
|
||||
imgPt1.create(1, (int)total, CV_64FC2);
|
||||
Mat imgPt2Mat;
|
||||
|
||||
Mat imgPt1Mat = imgPt1.getMat();
|
||||
if (!imagePoints2.empty())
|
||||
{
|
||||
imgPt2.create(1, (int)total, CV_32FC2);
|
||||
imgPtData2 = imgPt2.getMat().ptr<Point2f>();
|
||||
imgPt2.create(1, (int)total, CV_64FC2);
|
||||
imgPt2Mat = imgPt2.getMat();
|
||||
}
|
||||
|
||||
Mat nPointsMat = npoints.getMat();
|
||||
Mat objPtMat = objPt.getMat();
|
||||
Point3f* objPtData = objPtMat.ptr<Point3f>();
|
||||
Point2f* imgPtData1 = imgPt1.getMat().ptr<Point2f>();
|
||||
|
||||
for (int i = 0, j = 0; i < nimages; i++)
|
||||
{
|
||||
Mat objpt = objectPoints.getMat(i);
|
||||
Mat imgpt1 = imagePoints1.getMat(i);
|
||||
int numberOfObjectPoints = objpt.checkVector(3, CV_32F, false);
|
||||
int numberOfObjectPoints = std::max(objpt.checkVector(3, CV_32F, false), objpt.checkVector(3, CV_64F, false));
|
||||
if (!objpt.isContinuous())
|
||||
objpt = objpt.clone();
|
||||
if (!imgpt1.isContinuous())
|
||||
imgpt1 = imgpt1.clone();
|
||||
nPointsMat.at<int>(i) = numberOfObjectPoints;
|
||||
for (int n = 0; n < numberOfObjectPoints; ++n)
|
||||
{
|
||||
objPtData[j + n] = objpt.ptr<Point3f>()[n];
|
||||
imgPtData1[j + n] = imgpt1.ptr<Point2f>()[n];
|
||||
}
|
||||
Mat(1, numberOfObjectPoints, CV_MAKETYPE(objpt.depth(), 3), objpt.ptr())
|
||||
.convertTo(objPtMat.colRange(j, j + numberOfObjectPoints), CV_64F);
|
||||
Mat(1, numberOfObjectPoints, CV_MAKETYPE(imgpt1.depth(), 2), imgpt1.ptr())
|
||||
.convertTo(imgPt1Mat.colRange(j, j + numberOfObjectPoints), CV_64F);
|
||||
|
||||
if (imgPtData2)
|
||||
if (!imgPt2Mat.empty())
|
||||
{
|
||||
Mat imgpt2 = imagePoints2.getMat(i);
|
||||
int numberOfImage2Points = imgpt2.checkVector(2, CV_32F, false);
|
||||
int numberOfImage2Points = std::max(imgpt2.checkVector(2, CV_32F, false), imgpt2.checkVector(2, CV_64F, false));
|
||||
CV_CheckEQ(numberOfObjectPoints, numberOfImage2Points, "Number of object and image(2) points must be equal");
|
||||
if (!imgpt2.isContinuous())
|
||||
imgpt2 = imgpt2.clone();
|
||||
for (int n = 0; n < numberOfImage2Points; ++n)
|
||||
{
|
||||
imgPtData2[j + n] = imgpt2.ptr<Point2f>()[n];
|
||||
}
|
||||
Mat(1, numberOfImage2Points, CV_MAKETYPE(imgpt2.depth(), 2), imgpt2.ptr())
|
||||
.convertTo(imgPt2Mat.colRange(j, j + numberOfImage2Points), CV_64F);
|
||||
}
|
||||
|
||||
j += numberOfObjectPoints;
|
||||
@@ -2994,7 +2989,7 @@ double calibrateCameraRO(InputArrayOfArrays _objectPoints,
|
||||
int np = npoints.at<int>( 0 );
|
||||
Mat newObjPt;
|
||||
if( newobj_needed ) {
|
||||
newObjPoints.create( 1, np, CV_32FC3 );
|
||||
newObjPoints.create( 1, np, CV_MAKETYPE(_objectPoints.depth(0), 3) );
|
||||
newObjPt = newObjPoints.getMat();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include "opencv2/stereo.hpp"
|
||||
#include "opencv2/objdetect.hpp"
|
||||
#include <cfloat>
|
||||
#include "opencv2/ts/cuda_test.hpp"
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
@@ -2029,4 +2030,183 @@ TEST(Calib_CalibrateCamera, size4DistortionCoeffs)
|
||||
EXPECT_LE(cv::norm(cv::Vec4d(D2), distCoeffs, NORM_INF), 1e-4);
|
||||
}
|
||||
|
||||
static void makeFloat64Views(const Matx33d& K, const Vec3d& rStereo, const Vec3d& tStereo,
|
||||
std::vector<std::vector<Point3d> >& objectPoints,
|
||||
std::vector<std::vector<Point2d> >& imagePoints1,
|
||||
std::vector<std::vector<Point2d> >& imagePoints2)
|
||||
{
|
||||
std::vector<Point3d> board;
|
||||
for (int y = 0; y < 6; y++)
|
||||
for (int x = 0; x < 9; x++)
|
||||
board.push_back(Point3d(x * 0.025, y * 0.025, 0));
|
||||
|
||||
const Vec3d rvecs[] = { Vec3d(0.1, 0.2, 0), Vec3d(-0.2, 0.1, 0.1), Vec3d(0.3, -0.1, 0.05), Vec3d(0, -0.3, -0.1) };
|
||||
const Vec3d tvecs[] = { Vec3d(-0.1, -0.07, 0.5), Vec3d(-0.08, -0.06, 0.6), Vec3d(-0.12, -0.05, 0.55), Vec3d(-0.1, -0.08, 0.45) };
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Vec3d r2, t2;
|
||||
composeRT(rvecs[i], tvecs[i], rStereo, tStereo, r2, t2);
|
||||
std::vector<Point2d> p1, p2;
|
||||
projectPoints(board, rvecs[i], tvecs[i], K, noArray(), p1);
|
||||
projectPoints(board, r2, t2, K, noArray(), p2);
|
||||
objectPoints.push_back(board);
|
||||
imagePoints1.push_back(p1);
|
||||
imagePoints2.push_back(p2);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename S>
|
||||
static std::vector<std::vector<T> > toPointsOf(const std::vector<std::vector<S> >& src)
|
||||
{
|
||||
std::vector<std::vector<T> > dst(src.size());
|
||||
for (size_t i = 0; i < src.size(); i++)
|
||||
for (const S& p : src[i])
|
||||
dst[i].push_back(T(p));
|
||||
return dst;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static Mat toExplicitDimsMat(const std::vector<T>& pts, int cn)
|
||||
{
|
||||
int sz[] = { 1, (int)pts.size(), cn };
|
||||
return Mat(3, sz, CV_64F, (void*)pts.data()).clone();
|
||||
}
|
||||
|
||||
TEST(Calib_CalibrateCamera, float64Points)
|
||||
{
|
||||
const Matx33d K(800, 0, 320, 0, 800, 240, 0, 0, 1);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img, img2;
|
||||
makeFloat64Views(K, Vec3d::all(0), Vec3d(-0.1, 0, 0), obj, img, img2);
|
||||
|
||||
Mat K64, dist64, K32, dist32;
|
||||
std::vector<Mat> rvecs, tvecs;
|
||||
double rms64 = calibrateCamera(obj, img, Size(640, 480), K64, dist64, rvecs, tvecs);
|
||||
double rms32 = calibrateCamera(toPointsOf<Point3f>(obj), toPointsOf<Point2f>(img),
|
||||
Size(640, 480), K32, dist32, rvecs, tvecs);
|
||||
|
||||
EXPECT_LT(rms64, 1e-7);
|
||||
EXPECT_MAT_NEAR(K64, Mat(K), 1e-6);
|
||||
EXPECT_LT(rms32, 1e-3);
|
||||
EXPECT_MAT_NEAR(K32, Mat(K), 1e-2);
|
||||
}
|
||||
|
||||
TEST(Calib_CalibrateCamera, dims3PointArrays)
|
||||
{
|
||||
const Matx33d K(800, 0, 320, 0, 800, 240, 0, 0, 1);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img, img2;
|
||||
makeFloat64Views(K, Vec3d::all(0), Vec3d(-0.1, 0, 0), obj, img, img2);
|
||||
|
||||
std::vector<Mat> objDims3(obj.size()), imgDims3(img.size());
|
||||
for (size_t i = 0; i < obj.size(); i++)
|
||||
{
|
||||
objDims3[i] = toExplicitDimsMat(obj[i], 3);
|
||||
imgDims3[i] = toExplicitDimsMat(img[i], 2);
|
||||
ASSERT_EQ(objDims3[i].dims, 3);
|
||||
ASSERT_EQ(objDims3[i].checkVector(3), (int)obj[i].size());
|
||||
}
|
||||
|
||||
Mat Kref, distref, Kdims3, distdims3;
|
||||
std::vector<Mat> rvecs, tvecs;
|
||||
double rmsRef = calibrateCamera(obj, img, Size(640, 480), Kref, distref, rvecs, tvecs);
|
||||
double rmsDims3 = calibrateCamera(objDims3, imgDims3, Size(640, 480), Kdims3, distdims3, rvecs, tvecs);
|
||||
|
||||
EXPECT_LT(rmsRef, 1e-7);
|
||||
EXPECT_NEAR(rmsRef, rmsDims3, 1e-9);
|
||||
EXPECT_MAT_NEAR(Kref, Kdims3, 1e-9);
|
||||
EXPECT_MAT_NEAR(distref, distdims3, 1e-9);
|
||||
}
|
||||
|
||||
TEST(Calib_CalibrateCameraRO, float64Points)
|
||||
{
|
||||
const Matx33d K(800, 0, 320, 0, 800, 240, 0, 0, 1);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img, img2;
|
||||
makeFloat64Views(K, Vec3d::all(0), Vec3d(-0.1, 0, 0), obj, img, img2);
|
||||
std::vector<std::vector<Point3f> > obj32 = toPointsOf<Point3f>(obj);
|
||||
|
||||
Mat K64, dist64, K32, dist32;
|
||||
std::vector<Mat> rvecs, tvecs;
|
||||
std::vector<Point3d> newObj64;
|
||||
std::vector<Point3f> newObj32;
|
||||
double rms64 = calibrateCameraRO(obj, img, Size(640, 480), 8, K64, dist64, rvecs, tvecs, newObj64);
|
||||
double rms32 = calibrateCameraRO(obj32, toPointsOf<Point2f>(img), Size(640, 480), 8,
|
||||
K32, dist32, rvecs, tvecs, newObj32);
|
||||
|
||||
EXPECT_LT(rms64, 1e-7);
|
||||
EXPECT_MAT_NEAR(K64, Mat(K), 1e-6);
|
||||
EXPECT_MAT_NEAR(Mat(newObj64).reshape(1), Mat(obj[0]).reshape(1), 1e-9);
|
||||
EXPECT_LT(rms32, 1e-3);
|
||||
EXPECT_MAT_NEAR(K32, Mat(K), 1e-2);
|
||||
EXPECT_MAT_NEAR(Mat(newObj32).reshape(1), Mat(obj32[0]).reshape(1), 1e-4);
|
||||
}
|
||||
|
||||
TEST(Calib_StereoCalibrate, float64Points)
|
||||
{
|
||||
const Matx33d K(800, 0, 320, 0, 800, 240, 0, 0, 1);
|
||||
const Vec3d rStereo(0, 0.05, 0), tStereo(-0.1, 0, 0);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img1, img2;
|
||||
makeFloat64Views(K, rStereo, tStereo, obj, img1, img2);
|
||||
|
||||
Mat Rgt;
|
||||
Rodrigues(rStereo, Rgt);
|
||||
Mat K1 = Mat(K).clone(), K2 = Mat(K).clone(), D1 = Mat::zeros(1, 5, CV_64F), D2 = Mat::zeros(1, 5, CV_64F);
|
||||
Mat R64, T64, R32, T32;
|
||||
double rms64 = stereoCalibrate(obj, img1, img2, K1, D1, K2, D2, Size(640, 480),
|
||||
R64, T64, noArray(), noArray(), CALIB_FIX_INTRINSIC);
|
||||
double rms32 = stereoCalibrate(toPointsOf<Point3f>(obj), toPointsOf<Point2f>(img1), toPointsOf<Point2f>(img2),
|
||||
K1, D1, K2, D2, Size(640, 480),
|
||||
R32, T32, noArray(), noArray(), CALIB_FIX_INTRINSIC);
|
||||
|
||||
EXPECT_LT(rms64, 1e-7);
|
||||
EXPECT_MAT_NEAR(R64, Rgt, 1e-6);
|
||||
EXPECT_MAT_NEAR(T64, Mat(tStereo), 1e-6);
|
||||
EXPECT_LT(rms32, 1e-3);
|
||||
EXPECT_MAT_NEAR(R32, Rgt, 1e-4);
|
||||
EXPECT_MAT_NEAR(T32, Mat(tStereo), 1e-4);
|
||||
}
|
||||
|
||||
TEST(Calib_InitCameraMatrix2D, float64Points)
|
||||
{
|
||||
const Matx33d K(800, 0, 319.5, 0, 800, 239.5, 0, 0, 1);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img, img2;
|
||||
makeFloat64Views(K, Vec3d::all(0), Vec3d(-0.1, 0, 0), obj, img, img2);
|
||||
|
||||
Mat K64 = initCameraMatrix2D(obj, img, Size(640, 480));
|
||||
Mat K32 = initCameraMatrix2D(toPointsOf<Point3f>(obj), toPointsOf<Point2f>(img), Size(640, 480));
|
||||
|
||||
EXPECT_MAT_NEAR(K64, Mat(K), 1e-4);
|
||||
EXPECT_MAT_NEAR(K64, K32, 1e-2);
|
||||
}
|
||||
|
||||
TEST(Calib_RegisterCameras, float64Points)
|
||||
{
|
||||
const Matx33d K(800, 0, 320, 0, 800, 240, 0, 0, 1);
|
||||
const Vec3d rStereo(0, 0.05, 0), tStereo(-0.1, 0, 0);
|
||||
std::vector<std::vector<Point3d> > obj;
|
||||
std::vector<std::vector<Point2d> > img1, img2;
|
||||
makeFloat64Views(K, rStereo, tStereo, obj, img1, img2);
|
||||
|
||||
Mat Rgt;
|
||||
Rodrigues(rStereo, Rgt);
|
||||
Mat D = Mat::zeros(1, 5, CV_64F);
|
||||
Mat R64, T64, R32, T32, E, F, errs;
|
||||
double rms64 = registerCameras(obj, obj, img1, img2, K, D, CALIB_MODEL_PINHOLE, K, D, CALIB_MODEL_PINHOLE,
|
||||
R64, T64, E, F, errs);
|
||||
std::vector<std::vector<Point3f> > obj32 = toPointsOf<Point3f>(obj);
|
||||
double rms32 = registerCameras(obj32, obj32, toPointsOf<Point2f>(img1), toPointsOf<Point2f>(img2),
|
||||
K, D, CALIB_MODEL_PINHOLE, K, D, CALIB_MODEL_PINHOLE,
|
||||
R32, T32, E, F, errs);
|
||||
|
||||
EXPECT_LT(rms64, 1e-7);
|
||||
EXPECT_MAT_NEAR(R64, Rgt, 1e-6);
|
||||
EXPECT_MAT_NEAR(T64, Mat(tStereo), 1e-6);
|
||||
EXPECT_LT(rms32, 1e-3);
|
||||
EXPECT_MAT_NEAR(R32, Rgt, 1e-4);
|
||||
EXPECT_MAT_NEAR(T32, Mat(tStereo), 1e-4);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
Reference in New Issue
Block a user