35 #define VIDEO_MOD_AVAILABLE
36 #define SENSORS_MOD_AVAILABLE
37 #include <zed-open-capture/videocapture.hpp>
38 #include <zed-open-capture/sensorcapture.hpp>
61 inline std::vector<std::string> &
split(
const std::string &s,
char delim, std::vector<std::string> &elems) {
62 std::stringstream ss(s);
64 while (getline(ss, item, delim)) {
65 elems.push_back(item);
70 inline std::vector<std::string>
split(
const std::string &s,
char delim) {
71 std::vector<std::string> elems;
72 split(s, delim, elems);
79 ConfManager(std::string filename) {
82 SI_Error rc = ini_.LoadFile(filename_.c_str());
83 is_opened_ = !(rc < 0);
90 float getValue(std::string key,
float default_value = -1) {
92 std::vector<std::string> elems;
93 split(key,
':', elems);
95 return atof(ini_.GetValue(elems.front().c_str(), elems.back().c_str(),
std::to_string(default_value).c_str()));
100 void setValue(std::string key,
float value) {
102 std::vector<std::string> elems;
103 split(key,
':', elems);
105 ini_.SetValue(elems.front().c_str(), elems.back().c_str(),
std::to_string(value).c_str());
109 inline bool isOpened() {
114 std::string filename_;
119 bool checkFile(std::string path) {
120 std::ifstream
f(
path.c_str());
124 static inline std::string getRootHiddenDir() {
128 wchar_t szPath[MAX_PATH];
130 TCHAR szPath[MAX_PATH];
133 if (!SUCCEEDED(SHGetFolderPath(NULL, CSIDL_COMMON_APPDATA, NULL, 0, szPath)))
136 char snfile_path[MAX_PATH];
140 size_t newsize = strlen(szPath) + 1;
141 wchar_t * wcstring =
new wchar_t[newsize];
143 size_t convertedChars = 0;
144 mbstowcs_s(&convertedChars, wcstring, newsize, szPath, _TRUNCATE);
145 wcstombs(snfile_path, wcstring, MAX_PATH);
147 wcstombs(snfile_path, szPath, MAX_PATH);
154 std::string homepath = getenv(
"HOME");
155 std::string
filename = homepath +
"/zed/";
162 static inline std::string getHiddenDir() {
163 std::string
filename = getRootHiddenDir();
172 bool downloadCalibrationFile(
unsigned int serial_number, std::string &calibration_file) {
174 std::string
path = getHiddenDir();
175 char specific_name[128];
176 sprintf(specific_name,
"SN%d.conf", serial_number);
177 calibration_file =
path + specific_name;
178 if (!checkFile(calibration_file)) {
184 res = system(
cmd.c_str());
187 std::string
url(
"'https://calib.stereolabs.com/?SN=");
190 std::cout <<
cmd << std::endl;
191 res = system(
cmd.c_str());
193 if( res == EXIT_FAILURE )
195 std::cerr <<
"Error downloading the calibration file" << std::endl;
199 if (!checkFile(calibration_file)) {
200 std::cerr <<
"Invalid calibration file" << std::endl;
205 std::string
path = getHiddenDir();
206 char specific_name[128];
207 sprintf(specific_name,
"SN%d.conf", serial_number);
208 calibration_file =
path + specific_name;
209 if (!checkFile(calibration_file)) {
210 TCHAR *settingFolder =
new TCHAR[
path.size() + 1];
211 settingFolder[
path.size()] = 0;
212 std::copy(
path.begin(),
path.end(), settingFolder);
213 SHCreateDirectoryEx(NULL, settingFolder, NULL);
215 std::string
url(
"https://calib.stereolabs.com/?SN=");
217 TCHAR *address =
new TCHAR[
url.size() + 1];
218 address[
url.size()] = 0;
219 std::copy(
url.begin(),
url.end(), address);
220 TCHAR *calibPath =
new TCHAR[calibration_file.size() + 1];
221 calibPath[calibration_file.size()] = 0;
222 std::copy(calibration_file.begin(), calibration_file.end(), calibPath);
224 HRESULT hr = URLDownloadToFile(NULL, address, calibPath, 0, NULL);
226 std::cout <<
"Fail to download calibration file" << std::endl;
230 if (!checkFile(calibration_file)) {
231 std::cout <<
"Invalid calibration file" << std::endl;
242 if (!checkFile(calibration_file)) {
243 std::cout <<
"Calibration file missing." << std::endl;
248 ConfManager camerareader(calibration_file.c_str());
249 if (!camerareader.isOpened())
252 std::string resolution_str;
253 switch ((
int) image_size.width) {
255 resolution_str =
"2k";
258 resolution_str =
"fhd";
261 resolution_str =
"hd";
264 resolution_str =
"vga";
267 resolution_str =
"hd";
273 T_[0] = camerareader.getValue(
"stereo:baseline", 0.0f);
274 T_[1] = camerareader.getValue(
"stereo:ty_" + resolution_str, 0.f);
277 T_[1] = camerareader.getValue(
"stereo:ty", 0.f);
279 T_[2] = camerareader.getValue(
"stereo:tz_" + resolution_str, 0.f);
282 T_[2] = camerareader.getValue(
"stereo:tz", 0.f);
286 float left_cam_cx = camerareader.getValue(
"left_cam_" + resolution_str +
":cx", 0.0f);
287 float left_cam_cy = camerareader.getValue(
"left_cam_" + resolution_str +
":cy", 0.0f);
288 float left_cam_fx = camerareader.getValue(
"left_cam_" + resolution_str +
":fx", 0.0f);
289 float left_cam_fy = camerareader.getValue(
"left_cam_" + resolution_str +
":fy", 0.0f);
290 float left_cam_k1 = camerareader.getValue(
"left_cam_" + resolution_str +
":k1", 0.0f);
291 float left_cam_k2 = camerareader.getValue(
"left_cam_" + resolution_str +
":k2", 0.0f);
292 float left_cam_p1 = camerareader.getValue(
"left_cam_" + resolution_str +
":p1", 0.0f);
293 float left_cam_p2 = camerareader.getValue(
"left_cam_" + resolution_str +
":p2", 0.0f);
294 float left_cam_k3 = camerareader.getValue(
"left_cam_" + resolution_str +
":k3", 0.0f);
297 float right_cam_cx = camerareader.getValue(
"right_cam_" + resolution_str +
":cx", 0.0f);
298 float right_cam_cy = camerareader.getValue(
"right_cam_" + resolution_str +
":cy", 0.0f);
299 float right_cam_fx = camerareader.getValue(
"right_cam_" + resolution_str +
":fx", 0.0f);
300 float right_cam_fy = camerareader.getValue(
"right_cam_" + resolution_str +
":fy", 0.0f);
301 float right_cam_k1 = camerareader.getValue(
"right_cam_" + resolution_str +
":k1", 0.0f);
302 float right_cam_k2 = camerareader.getValue(
"right_cam_" + resolution_str +
":k2", 0.0f);
303 float right_cam_p1 = camerareader.getValue(
"right_cam_" + resolution_str +
":p1", 0.0f);
304 float right_cam_p2 = camerareader.getValue(
"right_cam_" + resolution_str +
":p2", 0.0f);
305 float right_cam_k3 = camerareader.getValue(
"right_cam_" + resolution_str +
":k3", 0.0f);
309 if (right_cam_k1 == 0 && left_cam_k1 == 0 && left_cam_k2 == 0 && right_cam_k2 == 0) {
310 UERROR(
"ZED File invalid");
312 std::string
cmd =
"rm " + calibration_file;
313 int res = system(
cmd.c_str());
314 if( res == EXIT_FAILURE )
323 cv::Mat R_zed = (cv::Mat_<double>(1, 3) << camerareader.getValue(
"stereo:rx_" + resolution_str, 0.f), camerareader.getValue(
"stereo:cv_" + resolution_str, 0.f), camerareader.getValue(
"stereo:rz_" + resolution_str, 0.f));
327 cv::Rodrigues(R_zed , R );
329 cv::Mat distCoeffs_left, distCoeffs_right;
332 cv::Mat cameraMatrix_left = (cv::Mat_<double>(3, 3) << left_cam_fx, 0, left_cam_cx, 0, left_cam_fy, left_cam_cy, 0, 0, 1);
333 distCoeffs_left = (cv::Mat_<double>(1, 5) << left_cam_k1, left_cam_k2, left_cam_p1, left_cam_p2, left_cam_k3);
336 cv::Mat cameraMatrix_right = (cv::Mat_<double>(3, 3) << right_cam_fx, 0, right_cam_cx, 0, right_cam_fy, right_cam_cy, 0, 0, 1);
337 distCoeffs_right = (cv::Mat_<double>(1, 5) << right_cam_k1, right_cam_k2, right_cam_p1, right_cam_p2, right_cam_k3);
340 cv::Mat
T = (cv::Mat_<double>(3, 1) << T_[0], T_[1], T_[2]);
347 cv::Mat
R1,
R2, P1, P2,
Q;
348 cv::stereoRectify(cameraMatrix_left, distCoeffs_left, cameraMatrix_right, distCoeffs_right, image_size, R,
T,
349 R1, R2, P1, P2,
Q, cv::CALIB_ZERO_DISPARITY, 0, image_size);
352 image_size, cameraMatrix_left, distCoeffs_left, R1, P1,
353 image_size, cameraMatrix_right, distCoeffs_right, R2, P2,
354 R,
T, cv::Mat(), cv::Mat(), localTransform);
365 class ZedOCThread:
public UThread
368 ZedOCThread(sl_oc::sensors::SensorCapture* sensCap,
const Transform & imuLocalTransform)
371 imuLocalTransform_ = imuLocalTransform;
375 const double & stamp,
380 if(imuBuffer_.empty())
391 while(maxWaitTimeMs > 0 && imuBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
399 if(imuBuffer_.rbegin()->first < stamp)
403 UWARN(
"Could not find imu data to interpolate at image time %f after waiting %d ms (last is %f)...", stamp, maxWaitTimeMs, imuBuffer_.rbegin()->first);
408 std::map<double, std::pair<cv::Vec3f, cv::Vec3f> >::const_iterator iterB = imuBuffer_.lower_bound(stamp);
409 std::map<double, std::pair<cv::Vec3f, cv::Vec3f> >::const_iterator iterA = iterB;
410 if(iterA != imuBuffer_.begin())
414 if(iterB == imuBuffer_.end())
418 if(iterA == iterB && stamp == iterA->first)
420 acc[0] = iterA->second.first[0];
421 acc[1] = iterA->second.first[1];
422 acc[2] = iterA->second.first[2];
423 gyr[0] = iterA->second.second[0];
424 gyr[1] = iterA->second.second[1];
425 gyr[2] = iterA->second.second[2];
428 else if(stamp >= iterA->first && stamp <= iterB->first)
430 float t = (stamp-iterA->first) / (iterB->first-iterA->first);
431 acc[0] = iterA->second.first[0] +
t*(iterB->second.first[0] - iterA->second.first[0]);
432 acc[1] = iterA->second.first[1] +
t*(iterB->second.first[1] - iterA->second.first[1]);
433 acc[2] = iterA->second.first[2] +
t*(iterB->second.first[2] - iterA->second.first[2]);
434 gyr[0] = iterA->second.second[0] +
t*(iterB->second.second[0] - iterA->second.second[0]);
435 gyr[1] = iterA->second.second[1] +
t*(iterB->second.second[1] - iterA->second.second[1]);
436 gyr[2] = iterA->second.second[2] +
t*(iterB->second.second[2] - iterA->second.second[2]);
441 if(stamp < iterA->first)
443 UDEBUG(
"Could not find imu data to interpolate at image time %f (earliest is %f). Are sensors synchronized? (may take some time to be synchronized...)", stamp, iterA->first);
447 UDEBUG(
"Could not find imu data to interpolate at image time %f (between %f and %f). Are sensors synchronized? (may take some time to be synchronized...)", stamp, iterA->first, iterB->first);
455 imu = IMU(gyr, cv::Mat::eye(3, 3, CV_64FC1),
456 acc, cv::Mat::eye(3, 3, CV_64FC1),
463 virtual void mainLoop()
466 const sl_oc::sensors::data::Imu imuData = sensCap_->getLastIMUData(2000);
469 if(imuData.valid == sl_oc::sensors::data::Imu::NEW_VAL )
472 static double deg2rad = 0.017453293;
473 std::pair<cv::Vec3d, cv::Vec3d> imu(
474 cv::Vec3d(imuData.aX, imuData.aY, imuData.aZ),
475 cv::Vec3d(imuData.gX*deg2rad, imuData.gY*deg2rad, imuData.gZ*deg2rad));
477 double stamp = double(imuData.timestamp)/10e8;
478 if(!imuBuffer_.empty() && imuBuffer_.rbegin()->first > stamp)
480 UWARN(
"IMU data not received in order, reset buffer! (previous=%f new=%f)", imuBuffer_.rbegin()->first, stamp);
483 imuBuffer_.insert(imuBuffer_.end(), std::make_pair(stamp, imu));
484 if(imuBuffer_.size() > 1000)
486 imuBuffer_.erase(imuBuffer_.begin());
491 sl_oc::sensors::SensorCapture* sensCap_;
492 Transform imuLocalTransform_;
494 std::map<double, std::pair<cv::Vec3f, cv::Vec3f> > imuBuffer_;
513 Camera(imageRate, localTransform)
519 usbDevice_(deviceId),
520 resolution_(resolution),
527 sl_oc::video::RESOLUTION
res =
static_cast<sl_oc::video::RESOLUTION
>(resolution_);
528 UASSERT(
res >= sl_oc::video::RESOLUTION::HD2K &&
res < sl_oc::video::RESOLUTION::LAST);
537 imuThread_->join(
true);
551 imuThread_->join(
true);
568 sl_oc::video::VideoParams
params;
569 params.res =
static_cast<sl_oc::video::RESOLUTION
>(resolution_);
571 params.fps = sl_oc::video::FPS::FPS_15;
574 params.fps = sl_oc::video::FPS::FPS_100;
578 params.fps = sl_oc::video::FPS::FPS_60;
582 params.fps = sl_oc::video::FPS::FPS_30;
587 params.verbose = sl_oc::VERBOSITY::INFO;
591 params.verbose = sl_oc::VERBOSITY::WARNING;
596 zed_ =
new sl_oc::video::VideoCapture(
params);
597 if( !zed_->initializeVideo(usbDevice_) )
599 UERROR(
"Cannot open camera video capture. Set log level <= info for more details.");
605 int sn = zed_->getSerialNumber();
606 UINFO(
"Connected to camera sn: %d", sn);
610 std::string calibration_file;
612 unsigned int serial_number = sn;
614 if( !downloadCalibrationFile(serial_number, calibration_file) )
616 UERROR(
"Could not load calibration file from Stereolabs servers");
621 UINFO(
"Calibration file found. Loading...");
625 zed_->getFrameSize(
w,
h);
629 if(initCalibration(calibration_file, cv::Size(
w/2,
h), stereoModel_, this->
getLocalTransform()))
633 std::cout <<
"Calibration left:" << std::endl << stereoModel_.left() << std::endl;
634 std::cout <<
"Calibration right:" << std::endl << stereoModel_.right() << std::endl;
636 stereoModel_.initRectificationMap();
640 sensors_ =
new sl_oc::sensors::SensorCapture((sl_oc::VERBOSITY)
params.verbose);
641 if( !sensors_->initializeSensors(serial_number) )
643 UERROR(
"Cannot open sensors capture. Set log level <= info for more details.");
649 UINFO(
"Sensors Capture connected to camera sn: %d", sensors_->getSerialNumber());
650 UINFO(
"Wait max 5 sec to see if the camera has imu...");
654 sensors_->getLastIMUData().valid != sl_oc::sensors::data::Imu::NEW_VAL)
661 UINFO(
"Camera doesn't have IMU sensor");
665 UINFO(
"Camera has IMU");
670 Transform imuLocalTransform_ = this->
getLocalTransform() *
Transform(0,1,0,0, 1,0,0,0, 0,0,-1,0);
672 imuThread_ =
new ZedOCThread(sensors_, imuLocalTransform_);
676 if(!zed_->enableSensorSync(sensors_))
678 UWARN(
"Failed to enable image/imu synchronization");
688 UERROR(
"CameraStereoZEDOC: RTAB-Map is not built with ZED Open Capture support!");
696 return stereoModel_.isValidForProjection();
707 return uFormat(
"%x", zed_->getSerialNumber());
722 bool imuReceived = imuThread_!=0;
726 const sl_oc::video::Frame frame = zed_->getLastFrame();
728 if(frame.data!=
nullptr && frame.timestamp!=lastStamp_)
730 lastStamp_ = frame.timestamp;
732 double stamp = double(lastStamp_)/10e8;
738 imuThread_->getIMU(stamp, imu, 10);
739 imuReceived = !imu.
empty();
742 UWARN(
"Waiting for synchronized imu (this can take several seconds when camera has been just started)...");
749 cv::Mat frameBGR, left, right;
752 cv::Mat frameYUV = cv::Mat( frame.height, frame.width, CV_8UC2, frame.data );
753 cv::cvtColor(frameYUV,frameBGR,cv::COLOR_YUV2BGR_YUYV);
757 left = frameBGR(cv::Rect(0, 0, frameBGR.cols / 2, frameBGR.rows));
758 cv::cvtColor(frameBGR(cv::Rect(frameBGR.cols / 2, 0, frameBGR.cols / 2, frameBGR.rows)),right,cv::COLOR_BGR2GRAY);
761 if(stereoModel_.isValidForRectification())
763 left = stereoModel_.left().rectifyImage(left);
764 right = stereoModel_.right().rectifyImage(right);
777 UERROR(
"CameraStereoZEDOC: Cannot get frame from the camera since 100 msec!");
786 UERROR(
"CameraStereoZEDOC: Cannot get synchronized IMU with camera for 15 sec!");
790 UERROR(
"CameraStereoZEDOC: RTAB-Map is not built with ZED Open Capture support!");