00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "posest/planarSFM.h"
00012 #include <iostream>
00013 #include <numeric>
00014 #include <functional>
00015 #include <stdio.h>
00016 #include <posest/test/simulated.h>
00017
00018 using namespace cv;
00019
00020 namespace pe
00021 {
00022
00023 void test()
00024 {
00025 vector<Point2f> points1, points2;
00026
00027 points1.resize(6);
00028 points2.resize(6);
00029
00030 points1[0] = Point2f(0, 0);
00031 points1[1] = Point2f(0, 1);
00032 points1[2] = Point2f(1, 0);
00033 points1[3] = Point2f(1, 1);
00034 points1[4] = Point2f(3, 0);
00035 points1[5] = Point2f(3, 1);
00036
00037 points2 = points1;
00038
00039 Mat H = findHomography(Mat(points1), Mat(points2), CV_RANSAC);
00040
00041 for(int i = 0; i < 3; i++)
00042 for(int j = 0; j < 3; j++)
00043 printf("%f ", H.at<float>(i, j));
00044
00045 }
00046
00047 void generatePlanarObject(vector<Point3f>& points, Point3f N, float d)
00048 {
00049
00050
00051
00052
00053
00054 Point3f N0 = N*(d/norm(N));
00055 for(size_t i = 0; i < points.size(); i++)
00056 {
00057 Point3f p(float(rand())/RAND_MAX, float(rand())/RAND_MAX, float(rand())/RAND_MAX);
00058 Point3f p_plane = crossProduct(p, N);
00059 points[i] = p_plane + N0;
00060 }
00061 }
00062
00063 void generatePlanarObject(vector<Point3f>& points, Point3f v1, Point3f v2, Vec2f limits1, Vec2f limits2, Point3f t)
00064 {
00065 for(size_t i = 0; i < points.size(); i++)
00066 {
00067 float scale1 = float(rand())/RAND_MAX*(limits1[1] - limits1[0]) + limits1[0];
00068 float scale2 = float(rand())/RAND_MAX*(limits2[1] - limits2[0]) + limits2[0];
00069 points[i] = v1*scale1 + v2*scale2 + t;
00070 }
00071 }
00072
00073
00074 void generate3DPointCloud(vector<Point3f>& points, Point3f pmin, Point3f pmax)
00075 {
00076 const Point3f delta = pmax - pmin;
00077 for(size_t i = 0; i < points.size(); i++)
00078 {
00079 Point3f p(float(rand())/RAND_MAX, float(rand())/RAND_MAX, float(rand())/RAND_MAX);
00080 p.x *= delta.x;
00081 p.y *= delta.y;
00082 p.z *= delta.z;
00083 p = p + pmin;
00084
00085 points[i] = p;
00086 }
00087 }
00088
00089 void addPointNoise(vector<Point2f>& points, double sigma = 3.0)
00090 {
00091 RNG rng(1);
00092 for(size_t i = 0; i < points.size(); i++)
00093 {
00094 points[i].x += 2*rand()*sigma/RAND_MAX - sigma;
00095 points[i].y += 2*rand()*sigma/RAND_MAX - sigma;
00096 }
00097 }
00098
00099 void addLinkNoise(vector<int>& indices, double ratio = 0.05)
00100 {
00101 const int count = int(indices.size()*ratio/2);
00102 for(size_t i = 0; i < count; i++)
00103 {
00104 int index1 = rand()%indices.size();
00105 int index2 = rand()%indices.size();
00106 std::swap(indices[index1], indices[index2]);
00107 }
00108 }
00109
00110 void addLinkNoise(vector<cv::DMatch>& indices, double ratio)
00111 {
00112 const int count = int(indices.size()*ratio/2);
00113 for(size_t i = 0; i < count; i++)
00114 {
00115 int index1 = rand()%indices.size();
00116 int index2 = rand()%indices.size();
00117 std::swap(indices[index1].trainIdx, indices[index2].trainIdx);
00118 }
00119 }
00120
00121 void generateIntrinsics(Mat& intrinsics)
00122 {
00123 intrinsics = Mat::eye(3, 3, CV_32F);
00124 intrinsics.at<float>(0, 0) = 400.0;
00125 intrinsics.at<float>(1, 1) = 400.0;
00126 intrinsics.at<float>(0, 2) = 640/2;
00127 intrinsics.at<float>(1, 2) = 480/2;
00128 }
00129
00130 void generateData(Mat& intrinsics, Mat& R, Mat& T, vector<KeyPoint>& points1, vector<KeyPoint>& points2, vector<int>& indices, vector<Point3f>& points)
00131 {
00132
00133
00134 Mat rvec1 = Mat::zeros(3, 1, CV_32F);
00135 Mat tvec1 = Mat::zeros(3, 1, CV_32F);
00136 Mat rvec2 = Mat::zeros(3, 1, CV_32F);
00137 Mat tvec2 = Mat::zeros(3, 1, CV_32F);
00138 tvec2.at<float>(0, 0) = 1.0f;
00139 rvec2.at<float>(0, 0) = 0.0f;
00140 tvec2.at<float>(1, 0) = 0.0f;
00141 generateIntrinsics(intrinsics);
00142 Mat dist_coeffs = Mat::zeros(5, 1, CV_32F);
00143
00144 vector<Point3f> planarPoints, pointCloud;
00145 planarPoints.resize(100);
00146 generatePlanarObject(planarPoints);
00147 pointCloud.resize(500);
00148 generate3DPointCloud(pointCloud);
00149
00150 points = planarPoints;
00151 points.insert(points.end(), pointCloud.begin(), pointCloud.end());
00152
00153 points1.resize(points.size());
00154 points2.resize(points.size());
00155 vector<Point2f> _points1, _points2;
00156 _points1.resize(points.size());
00157 _points2.resize(points.size());
00158
00159 projectPoints(Mat(points), rvec1, tvec1, intrinsics, dist_coeffs, _points1);
00160 projectPoints(Mat(points), rvec2, tvec2, intrinsics, dist_coeffs, _points2);
00161
00162 addPointNoise(_points1, 2.0);
00163 addPointNoise(_points2, 2.0);
00164
00165 indices.resize(points.size());
00166
00167 for(size_t i = 0; i < points1.size(); i++)
00168 {
00169 points1[i].pt = _points1[i];
00170 points2[i].pt = _points2[i];
00171 indices[i] = (int)i;
00172
00173
00174 }
00175
00176
00177
00178 vector<Point2f> _final1, _final2;
00179 keyPoints2Point2f(points1, _final1);
00180 keyPoints2Point2f(points2, _final2);
00181
00182 Rodrigues(rvec2, R);
00183 T = tvec2;
00184 Mat E = calcEssentialMatrix(intrinsics.inv(), R, tvec2);
00185 double error = avgSampsonusError(E, _final1, _final2);
00186 printf("Initial epipolar error: %f\n", error);
00187 }
00188
00189 void testReprojectPoints()
00190 {
00191 Mat intrinsics, R, T;
00192 vector<KeyPoint> _points1, _points2;
00193 vector<int> indices;
00194 vector<Point3f> points;
00195
00196 generateData(intrinsics, R, T, _points1, _points2, indices, points);
00197
00198 vector<Point2f> points1, points2;
00199 matchesFromIndices(_points1, _points2, indices, points1, points2);
00200
00201 vector<Point3f> _points;
00202 vector<bool> valid;
00203 reprojectPoints(intrinsics, R, T, points1, points2, _points, valid);
00204 float dist = norm(Mat(points) - Mat(_points))/sqrt(double(points.size()));
00205
00206 for(size_t i = 0; i < points.size(); i++)
00207 {
00208 printf("%d %f\n", i, norm(points[i] - _points[i]));
00209 }
00210 printf("%f %f %f | %f %f %f\n", points[0].x, points[0].y, points[0].z, _points[0].x, _points[0].y, _points[0].z);
00211 printf("reprojectPoints test: error is %f\n", dist);
00212 }
00213
00214 void generateProjections(const Mat& intrinsics, const Mat& rvec, const Mat& tvec, const vector<Point3f>& cloud, vector<KeyPoint>& keypoints)
00215 {
00216 Mat distCoeffs = Mat::zeros(5, 1, CV_32F);
00217 vector<Point2f> imagePoints;
00218 imagePoints.resize(cloud.size());
00219 projectPoints(Mat(cloud), rvec, tvec, intrinsics, distCoeffs, imagePoints);
00220
00221 for(size_t i = 0; i < imagePoints.size(); i++)
00222 {
00223 keypoints.push_back(KeyPoint(imagePoints[i], 1.0f));
00224 }
00225 }
00226
00227 void applyRT(const Mat& R, const Mat& T, const vector<Point3f>& points, vector<Point3f>& pointsRT)
00228 {
00229 Point3f t = T.at<Point3f>(0, 0);
00230 pointsRT.resize(points.size());
00231 for(size_t i = 0; i < points.size(); i++)
00232 {
00233 Point3f p = mult(R, points[i]);
00234 p = p + t;
00235 pointsRT[i] = p;
00236
00237
00238 }
00239 }
00240
00241 void calcVisible(const Mat& intrinsics, const Mat& R, const Mat& T,
00242 const vector<Point3f>& objectPoints, const vector<cv::KeyPoint>& imagePoints, vector<int>& visible)
00243 {
00244 visible.resize(imagePoints.size());
00245 vector<Point3f> cloudRT;
00246 applyRT(R, T, objectPoints, cloudRT);
00247
00248 float cx = intrinsics.at<float>(0, 2);
00249 float cy = intrinsics.at<float>(1, 2);
00250
00251 for(size_t i = 0; i < visible.size(); i++)
00252 {
00253 Point2f p = imagePoints[i].pt;
00254 if(cloudRT[i].z < 0 || p.x < 0 || p.y < 0 || p.x > 2*cx || p.y > 2*cy)
00255 {
00256 visible[i] = 0;
00257 }
00258 else
00259 {
00260 visible[i] = 1;
00261 }
00262
00263
00264
00265 }
00266 }
00267
00268 void generateCube(std::vector<cv::Point3f>& cloud)
00269 {
00270 const int facetCount = 10000;
00271 std::vector<cv::Point3f> facet;
00272 facet.resize(facetCount);
00273
00274 Vec2f limits(-1, 1);
00275 pe::generatePlanarObject(facet, Point3f(1, 0, 0), Point3f(0, 0, 1), limits, limits, Point3f(0, 1, 0));
00276 cloud.insert(cloud.end(), facet.begin(), facet.end());
00277 pe::generatePlanarObject(facet, Point3f(1, 0, 0), Point3f(0, 0, 1), limits, limits, Point3f(0, -1, 0));
00278 cloud.insert(cloud.end(), facet.begin(), facet.end());
00279 pe::generatePlanarObject(facet, Point3f(1, 0, 0), Point3f(0, 1, 0), limits, limits, Point3f(0, 0, 1));
00280 cloud.insert(cloud.end(), facet.begin(), facet.end());
00281 pe::generatePlanarObject(facet, Point3f(1, 0, 0), Point3f(0, 1, 0), limits, limits, Point3f(0, 0, -1));
00282 cloud.insert(cloud.end(), facet.begin(), facet.end());
00283
00284 printf("Generated %d points\n", (int)cloud.size());
00285 }
00286
00287 void generateRing(std::vector<cv::Point3f>& cloud, cv::Point3f center)
00288 {
00289 const int pointsCount = 10000;
00290 const float minRadius = 0.8;
00291 const float maxRadius = 1.1;
00292 for(int i = 0; i < 10000; i++)
00293 {
00294 float radius = float(rand())/RAND_MAX*(maxRadius - minRadius) + minRadius;
00295 float angle = float(rand())/RAND_MAX*2*CV_PI;
00296 float x = rand()%5 == 0 ? 0.05 : 0.0f;
00297
00298 cv::Point3f p(x, radius*cos(angle), radius*sin(angle));
00299 cloud.push_back(p + center);
00300 }
00301 }
00302
00303
00304 CircleCameraSimulator::CircleCameraSimulator(const cv::Mat& intrinsics, const std::vector<cv::Point3f>& cloud) :
00305 intrinsics_(intrinsics), cloud_(cloud), radius_(0.9f)
00306 {
00307 initRT();
00308 }
00309
00310 void CircleCameraSimulator::initRT()
00311 {
00312 rvec_ = Mat::zeros(3, 1, CV_32F);
00313 tvec_ = Mat::zeros(3, 1, CV_32F);
00314
00315
00316 tvec_.at<float>(0, 0) = 0.1;
00317 tvec_.at<float>(1, 0) = -radius_;
00318 angle_ = 0.0f;
00319 }
00320
00321 void CircleCameraSimulator::updateRT()
00322 {
00323 Mat oldTvec = tvec_.clone();
00324 Mat oldRvec = rvec_.clone();
00325
00326 angle_ -= 0.1f;
00327 rvec_.at<float>(0, 0) = angle_;
00328
00329
00330 Mat drvec, dtvec;
00331 calcRelativeRT(oldRvec, oldTvec, rvec_, tvec_, drvec, dtvec);
00332 dumpFltMat("Ground truth relative rvec", drvec);
00333 dumpFltMat("Ground truth relative tvec", dtvec);
00334 }
00335
00336 void CircleCameraSimulator::getNextFrame(std::vector<cv::KeyPoint>& imagePoints, std::vector<cv::DMatch>& matches)
00337 {
00338 updateRT();
00339
00340 std::vector<cv::KeyPoint> _imagePoints;
00341 generateProjections(intrinsics_, rvec_, tvec_, cloud_, _imagePoints);
00342
00343 Mat R;
00344 Rodrigues(rvec_, R);
00345 std::vector<int> visible;
00346 calcVisible(intrinsics_, R, tvec_, cloud_, _imagePoints, visible);
00347
00348 printf("%d points visible\n", std::accumulate(visible.begin(), visible.end(), 0));
00349 filterVector(_imagePoints, visible, imagePoints);
00350
00351 if(visible_.size() > 0)
00352 {
00353 calcMatches(visible, matches);
00354 }
00355 visible_ = visible;
00356 }
00357
00358 void CircleCameraSimulator::calcMatches(const std::vector<int>& newVisible, std::vector<cv::DMatch>& matches)
00359 {
00360 assert(visible_.size() == newVisible.size());
00361
00362 int index1 = 0, index2 = 0;
00363 for(size_t i = 0; i < newVisible.size(); i++)
00364 {
00365 if(visible_[i] && newVisible[i])
00366 {
00367 matches.push_back(cv::DMatch(index1, index2, 0.f));
00368 }
00369
00370 if(visible_[i]) index1++;
00371 if(newVisible[i]) index2++;
00372 }
00373 }
00374
00375 }