1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
5 // By downloading, copying, installing or using the software you agree to this license.
6 // If you do not agree to this license, do not download, install,
7 // copy or use the software.
11 // For Open Source Computer Vision Library
13 // Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
14 // Copyright (C) 2009, Willow Garage Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
17 // Redistribution and use in source and binary forms, with or without modification,
18 // are permitted provided that the following conditions are met:
20 // * Redistribution's of source code must retain the above copyright notice,
21 // this list of conditions and the following disclaimer.
23 // * Redistribution's in binary form must reproduce the above copyright notice,
24 // this list of conditions and the following disclaimer in the documentation
25 // and/or other materials provided with the distribution.
27 // * The name of the copyright holders may not be used to endorse or promote products
28 // derived from this software without specific prior written permission.
30 // This software is provided by the copyright holders and contributors "as is" and
31 // any express or implied warranties, including, but not limited to, the implied
32 // warranties of merchantability and fitness for a particular purpose are disclaimed.
33 // In no event shall the Intel Corporation or contributors be liable for any direct,
34 // indirect, incidental, special, exemplary, or consequential damages
35 // (including, but not limited to, procurement of substitute goods or services;
36 // loss of use, data, or profits; or business interruption) however caused
37 // and on any theory of liability, whether in contract, strict liability,
38 // or tort (including negligence or otherwise) arising in any way out of
39 // the use of this software, even if advised of the possibility of such damage.
43 #include "precomp.hpp"
49 bool cv::solvePnP( InputArray _opoints, InputArray _ipoints,
50 InputArray _cameraMatrix, InputArray _distCoeffs,
51 OutputArray _rvec, OutputArray _tvec, bool useExtrinsicGuess, int flags )
53 Mat opoints = _opoints.getMat(), ipoints = _ipoints.getMat();
54 int npoints = std::max(opoints.checkVector(3, CV_32F), opoints.checkVector(3, CV_64F));
55 CV_Assert( npoints >= 0 && npoints == std::max(ipoints.checkVector(2, CV_32F), ipoints.checkVector(2, CV_64F)) );
56 _rvec.create(3, 1, CV_64F);
57 _tvec.create(3, 1, CV_64F);
58 Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();
62 cv::Mat undistortedPoints;
63 cv::undistortPoints(ipoints, undistortedPoints, cameraMatrix, distCoeffs);
64 epnp PnP(cameraMatrix, opoints, undistortedPoints);
66 cv::Mat R, rvec = _rvec.getMat(), tvec = _tvec.getMat();
67 PnP.compute_pose(R, tvec);
68 cv::Rodrigues(R, rvec);
71 else if (flags == CV_P3P)
73 CV_Assert( npoints == 4);
74 cv::Mat undistortedPoints;
75 cv::undistortPoints(ipoints, undistortedPoints, cameraMatrix, distCoeffs);
76 p3p P3Psolver(cameraMatrix);
78 cv::Mat R, rvec = _rvec.getMat(), tvec = _tvec.getMat();
79 bool result = P3Psolver.solve(R, tvec, opoints, undistortedPoints);
81 cv::Rodrigues(R, rvec);
84 else if (flags == CV_ITERATIVE)
86 CvMat c_objectPoints = opoints, c_imagePoints = ipoints;
87 CvMat c_cameraMatrix = cameraMatrix, c_distCoeffs = distCoeffs;
88 CvMat c_rvec = _rvec.getMat(), c_tvec = _tvec.getMat();
89 cvFindExtrinsicCameraParams2(&c_objectPoints, &c_imagePoints, &c_cameraMatrix,
90 c_distCoeffs.rows*c_distCoeffs.cols ? &c_distCoeffs : 0,
91 &c_rvec, &c_tvec, useExtrinsicGuess );
95 CV_Error(CV_StsBadArg, "The flags argument must be one of CV_ITERATIVE or CV_EPNP");
103 const int MIN_POINTS_COUNT = 4;
105 static void project3dPoints(const Mat& points, const Mat& rvec, const Mat& tvec, Mat& modif_points)
107 modif_points.create(1, points.cols, CV_32FC3);
108 Mat R(3, 3, CV_64FC1);
110 Mat transformation(3, 4, CV_64F);
111 Mat r = transformation.colRange(0, 3);
113 Mat t = transformation.colRange(3, 4);
115 transform(points, modif_points, transformation);
133 resultsMutex.unlock();
139 tbb::mutex resultsMutex;
143 struct CameraParameters
145 void init(Mat _intrinsics, Mat _distCoeffs)
147 _intrinsics.copyTo(intrinsics);
148 _distCoeffs.copyTo(distortion);
158 float reprojectionError;
160 bool useExtrinsicGuess;
162 CameraParameters camera;
165 static void pnpTask(const vector<char>& pointsMask, const Mat& objectPoints, const Mat& imagePoints,
166 const Parameters& params, vector<int>& inliers, Mat& rvec, Mat& tvec,
167 const Mat& rvecInit, const Mat& tvecInit, Mutex& resultsMutex)
169 Mat modelObjectPoints(1, MIN_POINTS_COUNT, CV_32FC3), modelImagePoints(1, MIN_POINTS_COUNT, CV_32FC2);
170 for (int i = 0, colIndex = 0; i < (int)pointsMask.size(); i++)
174 Mat colModelImagePoints = modelImagePoints(Rect(colIndex, 0, 1, 1));
175 imagePoints.col(i).copyTo(colModelImagePoints);
176 Mat colModelObjectPoints = modelObjectPoints(Rect(colIndex, 0, 1, 1));
177 objectPoints.col(i).copyTo(colModelObjectPoints);
178 colIndex = colIndex+1;
182 //filter same 3d points, hang in solvePnP
184 int num_same_points = 0;
185 for (int i = 0; i < MIN_POINTS_COUNT; i++)
186 for (int j = i + 1; j < MIN_POINTS_COUNT; j++)
188 if (norm(modelObjectPoints.at<Vec3f>(0, i) - modelObjectPoints.at<Vec3f>(0, j)) < eps)
191 if (num_same_points > 0)
194 Mat localRvec, localTvec;
195 rvecInit.copyTo(localRvec);
196 tvecInit.copyTo(localTvec);
198 solvePnP(modelObjectPoints, modelImagePoints, params.camera.intrinsics, params.camera.distortion, localRvec, localTvec,
199 params.useExtrinsicGuess, params.flags);
202 vector<Point2f> projected_points;
203 projected_points.resize(objectPoints.cols);
204 projectPoints(objectPoints, localRvec, localTvec, params.camera.intrinsics, params.camera.distortion, projected_points);
207 project3dPoints(objectPoints, localRvec, localTvec, rotatedPoints);
209 vector<int> localInliers;
210 for (int i = 0; i < objectPoints.cols; i++)
212 Point2f p(imagePoints.at<Vec2f>(0, i)[0], imagePoints.at<Vec2f>(0, i)[1]);
213 if ((norm(p - projected_points[i]) < params.reprojectionError)
214 && (rotatedPoints.at<Vec3f>(0, i)[2] > 0)) //hack
216 localInliers.push_back(i);
220 if (localInliers.size() > inliers.size())
225 inliers.resize(localInliers.size());
226 memcpy(&inliers[0], &localInliers[0], sizeof(int) * localInliers.size());
227 localRvec.copyTo(rvec);
228 localTvec.copyTo(tvec);
230 resultsMutex.unlock();
237 void operator()( const BlockedRange& r ) const
239 vector<char> pointsMask(objectPoints.cols, 0);
240 memset(&pointsMask[0], 1, MIN_POINTS_COUNT );
241 for( int i=r.begin(); i!=r.end(); ++i )
243 generateVar(pointsMask);
244 pnpTask(pointsMask, objectPoints, imagePoints, parameters,
245 inliers, rvec, tvec, initRvec, initTvec, syncMutex);
246 if ((int)inliers.size() >= parameters.minInliersCount)
249 tbb::task::self().cancel_group_execution();
256 PnPSolver(const Mat& _objectPoints, const Mat& _imagePoints, const Parameters& _parameters,
257 Mat& _rvec, Mat& _tvec, vector<int>& _inliers):
258 objectPoints(_objectPoints), imagePoints(_imagePoints), parameters(_parameters),
259 rvec(_rvec), tvec(_tvec), inliers(_inliers)
261 rvec.copyTo(initRvec);
262 tvec.copyTo(initTvec);
265 PnPSolver& operator=(const PnPSolver&);
267 const Mat& objectPoints;
268 const Mat& imagePoints;
269 const Parameters& parameters;
271 vector<int>& inliers;
272 Mat initRvec, initTvec;
274 static RNG generator;
275 static Mutex syncMutex;
277 void generateVar(vector<char>& mask) const
279 int size = (int)mask.size();
280 for (int i = 0; i < size; i++)
282 int i1 = generator.uniform(0, size);
283 int i2 = generator.uniform(0, size);
284 char curr = mask[i1];
291 Mutex PnPSolver::syncMutex;
292 RNG PnPSolver::generator;
297 void cv::solvePnPRansac(InputArray _opoints, InputArray _ipoints,
298 InputArray _cameraMatrix, InputArray _distCoeffs,
299 OutputArray _rvec, OutputArray _tvec, bool useExtrinsicGuess,
300 int iterationsCount, float reprojectionError, int minInliersCount,
301 OutputArray _inliers, int flags)
303 Mat opoints = _opoints.getMat(), ipoints = _ipoints.getMat();
304 Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();
306 CV_Assert(opoints.isContinuous());
307 CV_Assert(opoints.depth() == CV_32F);
308 CV_Assert((opoints.rows == 1 && opoints.channels() == 3) || opoints.cols*opoints.channels() == 3);
309 CV_Assert(ipoints.isContinuous());
310 CV_Assert(ipoints.depth() == CV_32F);
311 CV_Assert((ipoints.rows == 1 && ipoints.channels() == 2) || ipoints.cols*ipoints.channels() == 2);
313 _rvec.create(3, 1, CV_64FC1);
314 _tvec.create(3, 1, CV_64FC1);
315 Mat rvec = _rvec.getMat();
316 Mat tvec = _tvec.getMat();
318 Mat objectPoints = opoints.reshape(3, 1), imagePoints = ipoints.reshape(2, 1);
320 if (minInliersCount <= 0)
321 minInliersCount = objectPoints.cols;
322 cv::pnpransac::Parameters params;
323 params.iterationsCount = iterationsCount;
324 params.minInliersCount = minInliersCount;
325 params.reprojectionError = reprojectionError;
326 params.useExtrinsicGuess = useExtrinsicGuess;
327 params.camera.init(cameraMatrix, distCoeffs);
328 params.flags = flags;
330 vector<int> localInliers;
331 Mat localRvec, localTvec;
332 rvec.copyTo(localRvec);
333 tvec.copyTo(localTvec);
335 if (objectPoints.cols >= pnpransac::MIN_POINTS_COUNT)
337 parallel_for(BlockedRange(0,iterationsCount), cv::pnpransac::PnPSolver(objectPoints, imagePoints, params,
338 localRvec, localTvec, localInliers));
341 if (localInliers.size() >= (size_t)pnpransac::MIN_POINTS_COUNT)
345 int i, pointsCount = (int)localInliers.size();
346 Mat inlierObjectPoints(1, pointsCount, CV_32FC3), inlierImagePoints(1, pointsCount, CV_32FC2);
347 for (i = 0; i < pointsCount; i++)
349 int index = localInliers[i];
350 Mat colInlierImagePoints = inlierImagePoints(Rect(i, 0, 1, 1));
351 imagePoints.col(index).copyTo(colInlierImagePoints);
352 Mat colInlierObjectPoints = inlierObjectPoints(Rect(i, 0, 1, 1));
353 objectPoints.col(index).copyTo(colInlierObjectPoints);
355 solvePnP(inlierObjectPoints, inlierImagePoints, params.camera.intrinsics, params.camera.distortion, localRvec, localTvec, true, flags);
357 localRvec.copyTo(rvec);
358 localTvec.copyTo(tvec);
359 if (_inliers.needed())
360 Mat(localInliers).copyTo(_inliers);
364 tvec.setTo(Scalar(0));
365 Mat R = Mat::eye(3, 3, CV_64F);
367 if( _inliers.needed() )