43 #include <opencv2/video/tracking.hpp> 52 const std::vector<cv::KeyPoint> & keypoints,
53 const cv::Mat & depth,
59 std::vector<CameraModel> models;
60 models.push_back(cameraModel);
65 const std::vector<cv::KeyPoint> & keypoints,
66 const cv::Mat & depth,
67 const std::vector<CameraModel> & cameraModels,
71 UASSERT(!depth.empty() && (depth.type() == CV_32FC1 || depth.type() == CV_16UC1));
73 std::vector<cv::Point3f> keypoints3d;
76 UASSERT(
int((depth.cols/cameraModels.size())*cameraModels.size()) == depth.cols);
77 float subImageWidth = depth.cols/cameraModels.size();
78 keypoints3d.resize(keypoints.size());
79 float rgbToDepthFactorX = 1.0f/(cameraModels[0].imageWidth()>0?cameraModels[0].imageWidth()/subImageWidth:1);
80 float rgbToDepthFactorY = 1.0f/(cameraModels[0].imageHeight()>0?cameraModels[0].imageHeight()/depth.rows:1);
81 float bad_point = std::numeric_limits<float>::quiet_NaN ();
82 for(
unsigned int i=0; i<keypoints.size(); ++i)
84 float x = keypoints[i].pt.x*rgbToDepthFactorX;
85 float y = keypoints[i].pt.y*rgbToDepthFactorY;
86 int cameraIndex = int(x / subImageWidth);
87 UASSERT_MSG(cameraIndex >= 0 && cameraIndex < (
int)cameraModels.size(),
88 uFormat(
"cameraIndex=%d, models=%d, kpt.x=%f, subImageWidth=%f (Camera model image width=%d)",
89 cameraIndex, (
int)cameraModels.size(), keypoints[i].pt.x, subImageWidth, cameraModels[0].imageWidth()).c_str());
92 cameraModels.size()==1?depth:cv::Mat(depth,
cv::Range::all(), cv::Range(subImageWidth*cameraIndex,subImageWidth*(cameraIndex+1))),
93 x-subImageWidth*cameraIndex,
95 cameraModels.at(cameraIndex).cx()*rgbToDepthFactorX,
96 cameraModels.at(cameraIndex).cy()*rgbToDepthFactorY,
97 cameraModels.at(cameraIndex).fx()*rgbToDepthFactorX,
98 cameraModels.at(cameraIndex).fy()*rgbToDepthFactorY,
101 cv::Point3f pt(bad_point, bad_point, bad_point);
103 (minDepth < 0.0f || ptXYZ.z > minDepth) &&
104 (maxDepth <= 0.0
f || ptXYZ.z <= maxDepth))
106 pt = cv::Point3f(ptXYZ.x, ptXYZ.y, ptXYZ.z);
107 if(!cameraModels.at(cameraIndex).localTransform().isNull() &&
108 !cameraModels.at(cameraIndex).localTransform().isIdentity())
113 keypoints3d.at(i) = pt;
120 const std::vector<cv::KeyPoint> & keypoints,
121 const cv::Mat & disparity,
126 UASSERT(!disparity.empty() && (disparity.type() == CV_16SC1 || disparity.type() == CV_32F));
128 std::vector<cv::Point3f> keypoints3d;
129 keypoints3d.resize(keypoints.size());
130 float bad_point = std::numeric_limits<float>::quiet_NaN ();
131 for(
unsigned int i=0; i!=keypoints.size(); ++i)
138 cv::Point3f pt(bad_point, bad_point, bad_point);
140 (minDepth < 0.0f || tmpPt.z > minDepth) &&
141 (maxDepth <= 0.0
f || tmpPt.z <= maxDepth))
150 keypoints3d.at(i) = pt;
156 const std::vector<cv::Point2f> & leftCorners,
157 const std::vector<cv::Point2f> & rightCorners,
159 const std::vector<unsigned char> &
mask,
163 UASSERT(leftCorners.size() == rightCorners.size());
164 UASSERT(mask.size() == 0 || leftCorners.size() == mask.size());
167 std::vector<cv::Point3f> keypoints3d;
168 keypoints3d.resize(leftCorners.size());
169 float bad_point = std::numeric_limits<float>::quiet_NaN ();
170 for(
unsigned int i=0; i<leftCorners.size(); ++i)
172 cv::Point3f pt(bad_point, bad_point, bad_point);
173 if(mask.empty() || mask[i])
175 float disparity = leftCorners[i].x - rightCorners[i].x;
176 if(disparity != 0.0
f)
184 (minDepth < 0.0f || tmpPt.z > minDepth) &&
185 (maxDepth <= 0.0
f || tmpPt.z <= maxDepth))
197 keypoints3d.at(i) = pt;
207 const std::map<int, cv::KeyPoint> & refWords,
208 const std::map<int, cv::KeyPoint> & nextWords,
212 float pnpReprojError,
214 int pnpRefineIterations,
217 const std::map<int, cv::Point3f> & refGuess3D,
218 double * varianceOut)
221 std::map<int, cv::Point3f> words3D;
222 std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
224 UDEBUG(
"pairsFound=%d/%d", pairsFound,
int(refWords.size()>nextWords.size()?refWords.size():nextWords.size()));
227 std::vector<unsigned char> status;
234 UASSERT(status.size() == pairs.size());
235 std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > >::iterator iter=pairs.begin();
236 std::vector<cv::Point2f> refCorners(status.size());
237 std::vector<cv::Point2f> newCorners(status.size());
238 std::vector<int> indexes(status.size());
239 for(
unsigned int i=0; i<status.size(); ++i)
243 refCorners[oi] = iter->second.first.pt;
244 newCorners[oi] = iter->second.second.pt;
245 indexes[oi] = iter->first;
250 refCorners.resize(oi);
251 newCorners.resize(oi);
254 UDEBUG(
"inliers=%d/%d", oi, pairs.size());
257 std::vector<cv::Point2f> refCornersRefined;
258 std::vector<cv::Point2f> newCornersRefined;
259 cv::correctMatches(F, refCorners, newCorners, refCornersRefined, newCornersRefined);
260 refCorners = refCornersRefined;
261 newCorners = newCornersRefined;
263 cv::Mat x(3, (
int)refCorners.size(), CV_64FC1);
264 cv::Mat xp(3, (
int)refCorners.size(), CV_64FC1);
265 for(
unsigned int i=0; i<refCorners.size(); ++i)
267 x.at<
double>(0, i) = refCorners[i].x;
268 x.at<
double>(1, i) = refCorners[i].y;
269 x.at<
double>(2, i) = 1;
271 xp.at<
double>(0, i) = newCorners[i].x;
272 xp.at<
double>(1, i) = newCorners[i].y;
273 xp.at<
double>(2, i) = 1;
276 cv::Mat K = cameraModel.
K();
277 cv::Mat Kinv = K.inv();
278 cv::Mat E = K.t()*F*K;
279 cv::Mat x_norm = Kinv * x;
280 cv::Mat xp_norm = Kinv * xp;
281 x_norm = x_norm.rowRange(0,2);
282 xp_norm = xp_norm.rowRange(0,2);
287 cv::Mat P0 = cv::Mat::zeros(3, 4, CV_64FC1);
288 P0.at<
double>(0,0) = 1;
289 P0.at<
double>(1,1) = 1;
290 P0.at<
double>(2,2) = 1;
292 bool useCameraTransformGuess = !cameraTransform.
isNull();
294 if(useCameraTransformGuess)
304 UDEBUG(
"Scale= %f", scale);
311 P = (cv::Mat_<double>(3,4) <<
312 (
double)t.
r11(), (double)t.
r12(), (double)t.
r13(), (double)t.
x(),
313 (double)t.
r21(), (double)t.
r22(), (double)t.
r23(), (double)t.
y(),
314 (double)t.
r31(), (double)t.
r32(), (double)t.
r33(), (double)t.
z());
322 cv::triangulatePoints(P0, P, x_norm, xp_norm, pts4D);
324 UASSERT((
int)indexes.size() == pts4D.cols && pts4D.rows == 4);
325 for(
unsigned int i=0; i<indexes.size(); ++i)
331 pts4D.col(i) /= pts4D.at<
double>(3,i);
332 if(pts4D.at<
double>(2,i) > 0)
334 words3D.insert(std::make_pair(indexes[i],
util3d::transformPoint(cv::Point3f(pts4D.at<
double>(0,i), pts4D.at<
double>(1,i), pts4D.at<
double>(2,i)), cameraModel.
localTransform())));
338 UDEBUG(
"ref guess=%d", (
int)refGuess3D.size());
339 if(refGuess3D.size())
342 std::vector<cv::Point3f> inliersRef;
343 std::vector<cv::Point3f> inliersRefGuess;
351 if(inliersRef.size())
355 float variance = 1.0f;
356 if(!useCameraTransformGuess)
358 std::multimap<float, float> scales;
359 for(
unsigned int i=0; i<inliersRef.size(); ++i)
362 float s = inliersRefGuess.at(i).x/inliersRef.at(i).x;
363 std::vector<float> errorSqrdDists(inliersRef.size());
364 for(
unsigned int j=0; j<inliersRef.size(); ++j)
366 cv::Point3f refPt = inliersRef.at(j);
370 const cv::Point3f & newPt = inliersRefGuess.at(j);
371 errorSqrdDists[j] =
uNormSquared(refPt.x-newPt.x, refPt.y-newPt.y, refPt.z-newPt.z);
373 std::sort(errorSqrdDists.begin(), errorSqrdDists.end());
374 double median_error_sqr = (double)errorSqrdDists[errorSqrdDists.size () >> 1];
375 float var = 2.1981 * median_error_sqr;
378 scales.insert(std::make_pair(var, s));
380 scale = scales.begin()->second;
381 variance = scales.begin()->first;;
386 std::vector<float> errorSqrdDists(inliersRef.size());
387 for(
unsigned int j=0; j<inliersRef.size(); ++j)
389 const cv::Point3f & refPt = inliersRef.at(j);
390 const cv::Point3f & newPt = inliersRefGuess.at(j);
391 errorSqrdDists[j] =
uNormSquared(refPt.x-newPt.x, refPt.y-newPt.y, refPt.z-newPt.z);
393 std::sort(errorSqrdDists.begin(), errorSqrdDists.end());
394 double median_error_sqr = (double)errorSqrdDists[errorSqrdDists.size () >> 1];
395 variance = 2.1981 * median_error_sqr;
398 UDEBUG(
"scale used = %f (variance=%f)", scale, variance);
401 *varianceOut = variance;
404 if(!useCameraTransformGuess)
406 std::vector<cv::Point3f> objectPoints(indexes.size());
407 std::vector<cv::Point2f> imagePoints(indexes.size());
409 UASSERT(indexes.size() == newCorners.size());
410 for(
unsigned int i=0; i<indexes.size(); ++i)
412 std::map<int, cv::Point3f>::iterator iter = words3D.find(indexes[i]);
415 iter->second.x *=
scale;
416 iter->second.y *=
scale;
417 iter->second.z *=
scale;
418 objectPoints[oi2].x = iter->second.x;
419 objectPoints[oi2].y = iter->second.y;
420 objectPoints[oi2].z = iter->second.z;
421 imagePoints[oi2] = newCorners[i];
425 objectPoints.resize(oi2);
426 imagePoints.resize(oi2);
430 cv::Mat R = (cv::Mat_<double>(3,3) <<
431 (
double)guess.
r11(), (double)guess.
r12(), (double)guess.
r13(),
432 (double)guess.
r21(), (double)guess.
r22(), (double)guess.
r23(),
433 (double)guess.
r31(), (double)guess.
r32(), (double)guess.
r33());
434 cv::Mat rvec(1,3, CV_64FC1);
435 cv::Rodrigues(R, rvec);
436 cv::Mat tvec = (cv::Mat_<double>(1,3) << (
double)guess.
x(), (double)guess.
y(), (double)guess.
z());
437 std::vector<int> inliersV;
451 pnpRefineIterations);
453 UDEBUG(
"PnP inliers = %d / %d", (
int)inliersV.size(), (int)objectPoints.size());
457 cv::Rodrigues(rvec, R);
458 Transform pnp(R.at<
double>(0,0), R.at<
double>(0,1), R.at<
double>(0,2), tvec.at<
double>(0),
459 R.at<
double>(1,0), R.at<
double>(1,1), R.at<
double>(1,2), tvec.at<
double>(1),
460 R.at<
double>(2,0), R.at<
double>(2,1), R.at<
double>(2,2), tvec.at<
double>(2));
466 UWARN(
"No inliers after PnP!");
472 UWARN(
"Cannot compute the scale, no points corresponding between the generated ref words and words guess");
475 else if(!useCameraTransformGuess)
480 Transform t(R.at<
double>(0,0), R.at<
double>(0,1), R.at<
double>(0,2), T.at<
double>(0),
481 R.at<
double>(1,0), R.at<
double>(1,1), R.at<
double>(1,2), T.at<
double>(1),
482 R.at<
double>(2,0), R.at<
double>(2,1), R.at<
double>(2,2), T.at<
double>(2));
490 UDEBUG(
"wordsSet=%d / %d", (
int)words3D.size(), (int)refWords.size());
496 const std::list<int> & wordIds,
497 const std::vector<cv::KeyPoint> & keypoints)
499 std::multimap<int, cv::KeyPoint> words;
500 std::vector<cv::KeyPoint>::const_iterator kpIter = keypoints.begin();
501 for(std::list<int>::const_iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
503 words.insert(std::pair<int, cv::KeyPoint >(*iter, *kpIter));
GLM_FUNC_DECL genIType mask(genIType const &count)
bool RTABMAP_EXP isFinite(const cv::Point3f &pt)
std::map< int, cv::Point3f > RTABMAP_EXP generateWords3DMono(const std::map< int, cv::KeyPoint > &kpts, const std::map< int, cv::KeyPoint > &previousKpts, const CameraModel &cameraModel, Transform &cameraTransform, int pnpIterations=100, float pnpReprojError=8.0f, int pnpFlags=0, int pnpRefineIterations=1, float ransacParam1=3.0f, float ransacParam2=0.99f, const std::map< int, cv::Point3f > &refGuess3D=std::map< int, cv::Point3f >(), double *variance=0)
cv::Point3f RTABMAP_EXP projectDisparityTo3D(const cv::Point2f &pt, float disparity, const StereoCameraModel &model)
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
static int findPairs(const std::map< int, cv::KeyPoint > &wordsA, const std::map< int, cv::KeyPoint > &wordsB, std::list< std::pair< int, std::pair< cv::KeyPoint, cv::KeyPoint > > > &pairs, bool ignoreNegativeIds=true)
GLM_FUNC_DECL bool all(vecType< bool, P > const &v)
Basic mathematics functions.
Some conversion functions.
static cv::Mat findFFromWords(const std::list< std::pair< int, std::pair< cv::KeyPoint, cv::KeyPoint > > > &pairs, std::vector< uchar > &status, double ransacParam1=3.0, double ransacParam2=0.99)
#define UASSERT(condition)
Wrappers of STL for convenient functions.
pcl::PointXYZ RTABMAP_EXP projectDepthTo3D(const cv::Mat &depthImage, float x, float y, float cx, float cy, float fx, float fy, bool smoothing, float depthErrorRatio=0.02f)
bool isValidForProjection() const
const CameraModel & left() const
std::multimap< int, cv::KeyPoint > RTABMAP_EXP aggregate(const std::list< int > &wordIds, const std::vector< cv::KeyPoint > &keypoints)
#define UASSERT_MSG(condition, msg_str)
static ULogger::Level level()
std::vector< cv::Point3f > RTABMAP_EXP generateKeypoints3DDisparity(const std::vector< cv::KeyPoint > &keypoints, const cv::Mat &disparity, const StereoCameraModel &stereoCameraModel, float minDepth=0, float maxDepth=0)
void RTABMAP_EXP solvePnPRansac(const std::vector< cv::Point3f > &objectPoints, const std::vector< cv::Point2f > &imagePoints, const cv::Mat &cameraMatrix, const cv::Mat &distCoeffs, cv::Mat &rvec, cv::Mat &tvec, bool useExtrinsicGuess, int iterationsCount, float reprojectionError, int minInliersCount, std::vector< int > &inliers, int flags, int refineIterations=1, float refineSigma=3.0f)
bool isValidForProjection() const
T uNormSquared(const std::vector< T > &v)
ULogger class and convenient macros.
static void findRTFromP(const cv::Mat &p, cv::Mat &r, cv::Mat &t)
std::vector< cv::Point3f > RTABMAP_EXP generateKeypoints3DDepth(const std::vector< cv::KeyPoint > &keypoints, const cv::Mat &depth, const CameraModel &cameraModel, float minDepth=0, float maxDepth=0)
const Transform & localTransform() const
static cv::Mat findPFromE(const cv::Mat &E, const cv::Mat &x, const cv::Mat &xp)
std::string UTILITE_EXP uFormat(const char *fmt,...)
void RTABMAP_EXP findCorrespondences(const std::multimap< int, cv::KeyPoint > &wordsA, const std::multimap< int, cv::KeyPoint > &wordsB, std::list< std::pair< cv::Point2f, cv::Point2f > > &pairs)
const Transform & localTransform() const
std::vector< cv::Point3f > RTABMAP_EXP generateKeypoints3DStereo(const std::vector< cv::Point2f > &leftCorners, const std::vector< cv::Point2f > &rightCorners, const StereoCameraModel &model, const std::vector< unsigned char > &mask=std::vector< unsigned char >(), float minDepth=0, float maxDepth=0)
GLM_FUNC_DECL matType< T, P > inverse(matType< T, P > const &m)