37 #include <opencv2/imgproc/types_c.h> 47 _rectifyImages(
false),
50 _depthScaleFactor(1.0
f),
56 _scanLocalTransform(
Transform::getIdentity()),
58 _depthFromScan(
false),
59 _depthFromScanFillHoles(1),
60 _depthFromScanFillHolesFromBorder(
false),
61 _filenamesAreTimestamps(
false),
62 _hasConfigForEachFrame(
false),
63 _syncImageRateWithStamps(
true),
65 _groundTruthFormat(0),
66 _maxPoseTimeDiff(0.02),
72 Camera(imageRate, localTransform),
140 UWARN(
"Directory is empty \"%s\"",
_path.c_str());
161 if(!_scanDir->isValid())
167 else if(_scanDir->getFileNames().size() == 0)
175 UERROR(
"Scan and image directories should be the same size \"%s\"(%d) vs \"%s\"(%d)",
177 (int)_scanDir->getFileNames().size(),
190 UINFO(
"calibration folder=%s name=%s", calibrationFolder.c_str(), cameraName.c_str());
191 if(!calibrationFolder.empty() && !cameraName.empty())
193 if(!
_model.
load(calibrationFolder, cameraName))
195 UWARN(
"Missing calibration files for camera \"%s\" in \"%s\" folder, you should calibrate the camera!",
196 cameraName.c_str(), calibrationFolder.c_str());
200 UINFO(
"Camera parameters: fx=%f fy=%f cx=%f cy=%f",
212 UERROR(
"Parameter \"rectifyImages\" is set, but no camera model is loaded or valid.");
224 #if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && CV_MAJOR_VERSION < 2) 231 bool modelsWarned =
false;
232 bool firstFrame =
true;
233 for(std::list<std::string>::const_iterator iter=dirJson.
getFileNames().begin(); iter!=dirJson.
getFileNames().end() && success; ++iter)
236 std::string filePath =
_path+
"/"+*iter;
237 cv::FileStorage fs(filePath, 0);
238 cv::FileNode poseNode = fs[
"cameraPoseARFrame"];
239 cv::FileNode timeNode = fs[
"time"];
240 cv::FileNode intrinsicsNode = fs[
"intrinsics"];
241 if(poseNode.isNone() || poseNode.size() != 16)
243 UERROR(
"Failed reading \"cameraPoseARFrame\" parameter, it should have 16 values (file=%s)", filePath.c_str());
247 else if(timeNode.isNone() || !timeNode.isReal())
249 UERROR(
"Failed reading \"time\" parameter (file=%s)", filePath.c_str());
253 else if(intrinsicsNode.isNone() || intrinsicsNode.size()!=9)
255 UERROR(
"Failed reading \"intrinsics\" parameter (file=%s)", filePath.c_str());
261 _stamps.push_back((
double)timeNode);
264 UWARN(
"Camera model loaded for each frame is overridden by " 265 "general calibration file provided. Remove general calibration " 266 "file to use camera model of each frame. This warning will " 267 "be shown only one time.");
273 (
double)intrinsicsNode[0],
274 (
double)intrinsicsNode[4],
275 (
double)intrinsicsNode[2],
276 (
double)intrinsicsNode[5],
281 (
float)poseNode[0], (
float)poseNode[1], (
float)poseNode[2], (
float)poseNode[3],
282 (
float)poseNode[4], (
float)poseNode[5], (
float)poseNode[6], (
float)poseNode[7],
283 (
float)poseNode[8], (
float)poseNode[9], (
float)poseNode[10], (
float)poseNode[11]);
287 cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1) * (firstFrame?9999.0:0.0001);
291 covariance.at<
double>(3,3) *= 0.01;
292 covariance.at<
double>(4,4) *= 0.01;
293 covariance.at<
double>(5,5) *= 0.01;
309 std::string opencv32warn;
310 #if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && CV_MAJOR_VERSION < 2) 311 opencv32warn =
" RTAB-Map is currently built with OpenCV < 3.2, only xml and yaml files are supported (not json).";
313 UERROR(
"Parameter \"Config for each frame\" is true, but the " 314 "number of config files (%d) is not equal to number " 315 "of images (%d) in this directory \"%s\".%s",
319 opencv32warn.c_str());
326 for(std::list<std::string>::const_iterator iter=filenames.begin(); iter!=filenames.end(); ++iter)
330 std::list<std::string> list =
uSplit(*iter,
'.');
331 if(list.size() == 3 || list.size() == 2)
337 std::list<std::string> numberList =
uSplitNumChar(list.front());
338 for(std::list<std::string>::iterator iter=numberList.begin(); iter!=numberList.end(); ++iter)
342 std::string decimals;
344 if(iter->length()>10)
346 decimals = iter->substr(10, iter->size()-10);
347 sec = iter->substr(0, 10);
371 UERROR(
"Conversion filename to timestamp failed! (filename=%s)", iter->c_str());
377 UERROR(
"The stamps count is not the same as the images (%d vs %d)! " 378 "Converting filenames to timestamps is activated.",
391 std::getline(file, str);
393 if(str.empty() || str.at(0) ==
'#' || str.at(0) ==
'%')
398 std::list<std::string> strList =
uSplit(str,
' ');
399 std::string stampStr = strList.front();
400 if(strList.size() == 2)
404 std::string millisecStr = strList.back();
405 while(millisecStr.size() < 6)
407 millisecStr =
"0" + millisecStr;
409 stampStr = stampStr+
'.'+millisecStr;
418 UERROR(
"The stamps count (%d) is not the same as the images (%d)! Please remove " 419 "the timestamps file path if you don't want to use them (current file path=%s).",
443 std::list<Transform> & outputPoses,
444 std::list<double> & inOutStamps,
445 const std::string & filePath,
447 double maxTimeDiff)
const 450 std::map<int, Transform> poses;
451 std::map<int, double> stamps;
454 UERROR(
"Cannot read pose file \"%s\".", filePath.c_str());
457 else if((format != 1 && format != 10 && format != 5 && format != 6 && format != 7 && format != 9) && poses.size() != this->
imagesCount())
459 UERROR(
"The pose count is not the same as the images (%d vs %d)! Please remove " 460 "the pose file path if you don't want to use it (current file path=%s).",
461 (
int)poses.size(), this->
imagesCount(), filePath.c_str());
464 else if((format == 1 || format == 10 || format == 5 || format == 6 || format == 7 || format == 9) && inOutStamps.size() == 0)
466 UERROR(
"When using RGBD-SLAM, GPS, MALAGA, ST LUCIA and EuRoC MAV formats, images must have timestamps!");
469 else if(format == 1 || format == 10 || format == 5 || format == 6 || format == 7 || format == 9)
474 std::map<double, int> stampsToIds;
475 for(std::map<int, double>::iterator iter=stamps.begin(); iter!=stamps.end(); ++iter)
477 stampsToIds.insert(std::make_pair(iter->second, iter->first));
479 std::vector<double> values =
uValues(stamps);
482 for(std::list<double>::iterator ster=inOutStamps.begin(); ster!=inOutStamps.end(); ++ster)
485 std::map<double, int>::iterator endIter = stampsToIds.lower_bound(*ster);
487 if(endIter != stampsToIds.end())
489 if(endIter->first == *ster)
491 pose = poses.at(endIter->second);
493 else if(endIter != stampsToIds.begin())
496 std::map<double, int>::iterator beginIter = endIter;
498 double stampBeg = beginIter->first;
499 double stampEnd = endIter->first;
500 UASSERT(stampEnd > stampBeg && *ster>stampBeg && *ster < stampEnd);
501 if(fabs(*ster-stampEnd) > maxTimeDiff || fabs(*ster-stampBeg) > maxTimeDiff)
505 UWARN(
"Cannot interpolate pose for stamp %f between %f and %f (> maximum time diff of %f sec)",
516 float t = (*ster - stampBeg) / (stampEnd-stampBeg);
517 Transform & ta = poses.at(beginIter->second);
518 Transform & tb = poses.at(endIter->second);
527 if(pose.
isNull() && !warned)
529 UDEBUG(
"Pose not found for stamp %f", *ster);
531 outputPoses.push_back(pose);
533 if(validPoses != (
int)inOutStamps.size())
535 UWARN(
"%d valid poses of %d stamps", validPoses, (
int)inOutStamps.size());
542 if(inOutStamps.size() == 0 && stamps.size() == poses.size())
546 else if(format==8 && inOutStamps.size() == 0 && stamps.size()>0 && stamps.size() != poses.size())
548 UERROR(
"With Karlsruhe format, timestamps (%d) and poses (%d) should match!", (
int)stamps.size(), (int)poses.size());
551 else if(!outputPoses.empty() && inOutStamps.empty() && stamps.empty())
553 UERROR(
"Timestamps are empty (poses=%d)! Forgot the set a timestamp file?", (
int)outputPoses.size());
557 UASSERT_MSG(outputPoses.size() == inOutStamps.size(),
uFormat(
"%d vs %d", (
int)outputPoses.size(), (int)inOutStamps.size()).c_str());
586 return std::vector<std::string>();
598 else if(sleepTime < 0)
602 UWARN(
"CameraImages: Cannot read images as fast as their timestamps (target delay=%fs, capture time=%fs). Disable " 603 "source image rate or disable synchronization of capture time with timestamps.",
608 UWARN(
"CameraImages: Cannot read images as fast as their timestamps (target delay=%fs, capture time=%fs).",
628 cv::Mat depthFromScan;
641 std::string imageFilePath;
642 std::string scanFilePath;
657 if(scanFileNames.size())
699 std::string fileName;
701 if(!fileName.empty())
703 imageFilePath =
_path + fileName;
736 imageFilePath =
_path + fileName;
771 if(!fileName.empty())
785 if(!imageFilePath.empty())
789 #if CV_MAJOR_VERSION >2 || (CV_MAJOR_VERSION >=2 && CV_MINOR_VERSION >=4) 790 img = cv::imread(imageFilePath.c_str(), cv::IMREAD_UNCHANGED);
792 img = cv::imread(imageFilePath.c_str(), -1);
794 UDEBUG(
"width=%d, height=%d, channels=%d, elementSize=%d, total=%d",
795 img.cols, img.rows, img.channels(), img.elemSize(), img.total());
799 if(img.type() != CV_16UC1 && img.type() != CV_32FC1)
801 UERROR(
"Depth is on and the loaded image has not a format supported (file = \"%s\", type=%d). " 802 "Formats supported are 16 bits 1 channel (mm) and 32 bits 1 channel (m).",
803 imageFilePath.c_str(), img.type());
814 #if CV_MAJOR_VERSION < 3 816 if(img.depth() != CV_8U)
819 UWARN(
"Cannot read the image correctly, falling back to old OpenCV C interface...");
820 IplImage * i = cvLoadImage(imageFilePath.c_str());
821 img = cv::Mat(i,
true);
827 UWARN(
"Conversion from 4 channels to 3 channels (file=%s)", imageFilePath.c_str());
829 cv::cvtColor(img, out, CV_BGRA2BGR);
834 cv::Mat debayeredImg;
837 cv::cvtColor(img, debayeredImg, CV_BayerBG2BGR +
_bayerMode);
840 catch(
const cv::Exception &
e)
842 UWARN(
"Error debayering images: \"%s\". Please set bayer mode to -1 if images are not bayered!", e.what());
853 if(!scanFilePath.empty())
858 UDEBUG(
"Loaded scan=%d points", (
int)scan.
size());
861 UDEBUG(
"Computing depth from scan...");
864 UWARN(
"Depth from laser scan: Camera model should be valid.");
868 UWARN(
"Depth from laser scan: Loading already a depth image.");
885 UWARN(
"Directory is not set, camera must be initialized.");
896 if(info && !odometryPose.
isNull())
899 info->
odomCovariance = covariance.empty()?cv::Mat::eye(6,6,CV_64FC1):covariance;
void setLocalTransform(const Transform &transform)
std::list< Transform > groundTruth_
bool _hasConfigForEachFrame
Transform _scanLocalTransform
void setImageSize(const cv::Size &size)
std::list< CameraModel > _models
std::string _groundTruthPath
std::string _lastFileName
const cv::Mat & data() const
const std::string & name() const
double UTILITE_EXP uStr2Double(const std::string &str)
GLM_FUNC_DECL genType sec(genType const &angle)
const std::list< std::string > & getFileNames() const
const Transform & getLocalTransform() const
int uStrNumCmp(const std::string &a, const std::string &b)
virtual SensorData captureImage(CameraInfo *info=0)
GLM_FUNC_DECL genType e()
std::list< V > uValuesList(const std::multimap< K, V > &mm)
unsigned int imagesCount() const
bool load(const std::string &filePath)
Some conversion functions.
static Transform opticalRotation()
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_EXP laserScanToPointCloud(const LaserScan &laserScan, const Transform &transform=Transform())
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
#define UASSERT(condition)
Wrappers of STL for convenient functions.
virtual bool isCalibrated() const
std::list< double > _stamps
std::string _odometryPath
#define ULOGGER_DEBUG(...)
void setPath(const std::string &path, const std::string &extensions="")
#define UASSERT_MSG(condition, msg_str)
int _depthFromScanFillHoles
std::string _lastScanFileName
bool readPoses(std::list< Transform > &outputPoses, std::list< double > &stamps, const std::string &filePath, int format, double maxTimeDiff) const
const CameraModel & cameraModel() const
bool isValidForRectification() const
Transform localTransform() const
std::list< std::string > uSplitNumChar(const std::string &str)
bool uIsNumber(const std::string &str)
std::vector< std::string > filenames() const
std::list< Transform > odometry_
bool _depthFromScanFillHolesFromBorder
cv::Mat rectifyImage(const cv::Mat &raw, int interpolation=cv::INTER_LINEAR) const
void uSleep(unsigned int ms)
std::vector< V > uListToVector(const std::list< V > &list)
bool isValidForProjection() const
float getImageRate() const
std::vector< V > uValues(const std::multimap< K, V > &mm)
bool _syncImageRateWithStamps
std::string getNextFileName()
std::string _timestampsPath
bool RTABMAP_EXP importPoses(const std::string &filePath, int format, std::map< int, Transform > &poses, std::multimap< int, Link > *constraints=0, std::map< int, double > *stamps=0)
virtual std::string getSerial() const
virtual bool init(const std::string &calibrationFolder=".", const std::string &cameraName="")
void RTABMAP_EXP fillProjectedCloudHoles(cv::Mat &depthRegistered, bool verticalDirection, bool fillToBorder)
cv::Mat RTABMAP_EXP projectCloudToCamera(const cv::Size &imageSize, const cv::Mat &cameraMatrixK, const cv::Mat &laserScan, const rtabmap::Transform &cameraTransform)
void setGroundTruth(const Transform &pose)
bool _filenamesAreTimestamps
#define ULOGGER_ERROR(...)
LaserScan RTABMAP_EXP loadScan(const std::string &path)
std::string UTILITE_EXP uFormat(const char *fmt,...)
void setName(const std::string &name)
std::list< cv::Mat > covariances_
const Transform & localTransform() const