00001 #include "posest/pnp_ransac.h"
00002 #include <iostream>
00003 #include "tbb/parallel_for.h"
00004 #include "tbb/blocked_range.h"
00005 #include "tbb/task_scheduler_init.h"
00006 #include "tbb/mutex.h"
00007
00008 using namespace std;
00009 using namespace cv;
00010 using namespace tbb;
00011
00012 void project3dPoints(const vector<Point3f>& points, const Mat& rvec, const Mat& tvec, vector<Point3f>& modif_points)
00013 {
00014 modif_points.clear();
00015 modif_points.resize(points.size());
00016 Mat R(3, 3, CV_64FC1);
00017 Rodrigues(rvec, R);
00018 for (size_t i = 0; i < points.size(); i++)
00019 {
00020 modif_points[i].x = R.at<double> (0, 0) * points[i].x + R.at<double> (0, 1) * points[i].y + R.at<double> (0, 2)
00021 * points[i].z + tvec.at<double> (0, 0);
00022 modif_points[i].y = R.at<double> (1, 0) * points[i].x + R.at<double> (1, 1) * points[i].y + R.at<double> (1, 2)
00023 * points[i].z + tvec.at<double> (1, 0);
00024 modif_points[i].z = R.at<double> (2, 0) * points[i].x + R.at<double> (2, 1) * points[i].y + R.at<double> (2, 2)
00025 * points[i].z + tvec.at<double> (2, 0);
00026 }
00027 }
00028
00029 void generateVar(vector<char>& mask, RNG& rng)
00030 {
00031 size_t size = mask.size();
00032 for (size_t i = 0; i < size; i++)
00033 {
00034 int i1 = rng.uniform(0, size);
00035 int i2 = rng.uniform(0, size);
00036 char curr = mask[i1];
00037 mask[i1] = mask[i2];
00038 mask[i2] = curr;
00039 }
00040 }
00041
00042 void pnpTask(const vector<char>& used_points_mask, const Mat& camera_matrix, const Mat& dist_coeffs,
00043 const vector<Point3f>& object_points, const vector<Point2f>& image_points, vector<int>& inliers,
00044 float max_dist, cv::Mat& rvec, cv::Mat& tvec, bool use_extrinsic_guess, const Mat& rvecInit,
00045 const Mat& tvecInit, tbb::mutex& Mutex)
00046 {
00047 vector<Point3f> model_object_points;
00048 vector<Point2f> model_image_points;
00049 for (size_t i = 0; i < used_points_mask.size(); i++)
00050 {
00051 if (used_points_mask[i])
00052 {
00053 model_image_points.push_back(image_points[i]);
00054 model_object_points.push_back(object_points[i]);
00055 }
00056 }
00057
00058 Mat rvecl, tvecl;
00059 rvecInit.copyTo(rvecl);
00060 tvecInit.copyTo(tvecl);
00061
00062
00063 double eps = 1e-10;
00064 int num_same_points = 0;
00065 for (int i = 0; i < MIN_POINTS_COUNT; i++)
00066 for (int j = i + 1; j < MIN_POINTS_COUNT; j++)
00067 if (norm(model_object_points[i] - model_object_points[j]) < eps)
00068 num_same_points++;
00069 if (num_same_points > 0)
00070 return;
00071
00072 solvePnP(Mat(model_object_points), Mat(model_image_points), camera_matrix, dist_coeffs, rvecl, tvecl, use_extrinsic_guess);
00073
00074 vector<Point2f> projected_points;
00075 projected_points.resize(object_points.size());
00076 projectPoints(Mat(object_points), rvecl, tvecl, camera_matrix, dist_coeffs, projected_points);
00077
00078 vector<Point3f> rotated_points;
00079 project3dPoints(object_points, rvecl, tvecl, rotated_points);
00080
00081 vector<int> inliers_indexes;
00082 for (size_t i = 0; i < object_points.size(); i++)
00083 {
00084 if ((norm(image_points[i] - projected_points[i]) < max_dist) && (rotated_points[i].z > 0))
00085 {
00086 inliers_indexes.push_back(i);
00087 }
00088 }
00089
00090 if (inliers_indexes.size() > inliers.size())
00091 {
00092 mutex::scoped_lock lock;
00093 lock.acquire(Mutex);
00094
00095 inliers.clear();
00096 inliers.resize(inliers_indexes.size());
00097 memcpy(&inliers[0], &inliers_indexes[0], sizeof(int) * inliers_indexes.size());
00098 rvecl.copyTo(rvec);
00099 tvecl.copyTo(tvec);
00100
00101 lock.release();
00102 }
00103 }
00104 void Iterate(const vector<Point3f>& object_points, const vector<Point2f>& image_points,
00105 const Mat& camera_matrix, const Mat& dist_coeffs, Mat& rvec, Mat& tvec, const float max_dist, const int min_inlier_num,
00106 vector<int>* inliers, bool use_extrinsic_guess, const Mat& rvecInit, const Mat& tvecInit, RNG& rng, tbb::mutex& Mutex)
00107 {
00108 vector<char> used_points_mask(object_points.size(), 0);
00109 memset(&used_points_mask[0], 1, MIN_POINTS_COUNT );
00110 generateVar(used_points_mask, rng);
00111 pnpTask(used_points_mask, camera_matrix, dist_coeffs, object_points, image_points,
00112 *inliers, max_dist, rvec, tvec, use_extrinsic_guess, rvecInit, tvecInit, Mutex);
00113 if ((int)inliers->size() > min_inlier_num)
00114 task::self().cancel_group_execution();
00115 }
00116
00117 class Iterator
00118 {
00119 const vector<Point3f>* object_points;
00120 const vector<Point2f>* image_points;
00121 const Mat* camera_matrix;
00122 const Mat* dist_coeffs;
00123 Mat* resultRvec, rvecInit;
00124 Mat* resultTvec, tvecInit;
00125 const float max_dist;
00126 const int min_inlier_num;
00127 vector<int>* inliers;
00128 bool use_extrinsic_guess;
00129 RNG* rng;
00130 static mutex ResultsMutex;
00131 public:
00132 void operator()( const blocked_range<size_t>& r ) const {
00133 for( size_t i=r.begin(); i!=r.end(); ++i )
00134 {
00135 Iterate(*object_points, *image_points, *camera_matrix, *dist_coeffs,
00136 *resultRvec, *resultTvec, max_dist, min_inlier_num,
00137 inliers, use_extrinsic_guess, rvecInit, tvecInit, *rng, ResultsMutex);
00138 }
00139 }
00140 Iterator(const vector<Point3f>* tobject_points, const vector<Point2f>* timage_points,
00141 const Mat* tcamera_matrix, const Mat* tdist_coeffs, Mat* rvec, Mat* tvec,
00142 float tmax_dist, int tmin_inlier_num, vector<int>* tinliers,
00143 bool tuse_extrinsic_guess, RNG* trng):
00144 object_points(tobject_points), image_points(timage_points),
00145 camera_matrix(tcamera_matrix), dist_coeffs(tdist_coeffs), resultRvec(rvec), resultTvec(tvec),
00146 max_dist(tmax_dist), min_inlier_num(tmin_inlier_num), inliers(tinliers),
00147 use_extrinsic_guess(tuse_extrinsic_guess), rng(trng)
00148 {
00149 resultRvec->copyTo(rvecInit);
00150 resultTvec->copyTo(tvecInit);
00151 }
00152 };
00153 mutex Iterator::ResultsMutex;
00154
00155 bool solvePnPRansac(const vector<Point3f>& object_points, const vector<Point2f>& image_points,
00156 const Mat& camera_matrix, const Mat& dist_coeffs, Mat& rvec, Mat& tvec, bool use_extrinsic_guess,
00157 int num_iterations, float max_dist, int min_inlier_num, vector<int>* inliers)
00158 {
00159 assert(object_points.size() == image_points.size());
00160
00161 if (object_points.size() < MIN_POINTS_COUNT)
00162 return false;
00163
00164 if (!use_extrinsic_guess)
00165 {
00166 rvec.create(3, 1, CV_64FC1);
00167 tvec.create(3, 1, CV_64FC1);
00168 }
00169 else
00170 {
00171 assert(rvec.rows == 3);
00172 assert(tvec.rows == 3);
00173 assert(rvec.cols == 1);
00174 assert(tvec.cols == 1);
00175 assert(rvec.type() == CV_64FC1);
00176 }
00177
00178 if (min_inlier_num == -1)
00179 min_inlier_num = object_points.size();
00180
00181 vector<int> local_inliers;
00182 if (!inliers)
00183 {
00184 inliers = &local_inliers;
00185 }
00186
00187 RNG rng;
00188 Mat rvecl(3, 1, CV_64FC1), tvecl(3, 1, CV_64FC1);
00189 rvec.copyTo(rvecl);
00190 tvec.copyTo(tvecl);
00191
00192 task_scheduler_init TBBinit;
00193 parallel_for(blocked_range<size_t>(0,num_iterations), Iterator(&object_points, &image_points,
00194 &camera_matrix, &dist_coeffs, &rvecl, &tvecl, max_dist,
00195 min_inlier_num, inliers, use_extrinsic_guess, &rng));
00196
00197 if ((int)(*inliers).size() >= MIN_POINTS_COUNT)
00198 {
00199 vector<Point3f> model_object_points;
00200 vector<Point2f> model_image_points;
00201 int index;
00202 for (size_t i = 0; i < (*inliers).size(); i++)
00203 {
00204 index = (*inliers)[i];
00205 model_image_points.push_back(image_points[index]);
00206 model_object_points.push_back(object_points[index]);
00207 }
00208 rvecl.copyTo(rvec);
00209 tvecl.copyTo(tvec);
00210 solvePnP(Mat(model_object_points), Mat(model_image_points), camera_matrix, dist_coeffs, rvec, tvec, true);
00211 }
00212 else
00213 {
00214 rvec.setTo(Scalar::all(0));
00215 tvec.setTo(Scalar::all(0));
00216 return false;
00217 }
00218 return true;
00219 }