13#include <RobotsIO/Camera/Camera.h>
14#include <RobotsIO/Camera/CameraDeprojectionMatrix.h>
15#include <RobotsIO/Utils/FileToDepth.h>
16#include <RobotsIO/Utils/Parameters.h>
18#include <opencv2/core/eigen.hpp>
24using namespace RobotsIO::Camera;
25using namespace RobotsIO::Utils;
36bool Camera::status()
const
55 if (!deprojection_matrix_initialized_)
56 return std::make_pair(
false, MatrixXd());
58 return std::make_pair(
true, deprojection_matrix_);
62std::pair<bool, CameraParameters> Camera::parameters()
const
64 if (!(parameters_.initialized()))
67 return std::make_pair(
true, parameters_);
71std::pair<bool, Eigen::MatrixXd> Camera::point_cloud
74 const double& maximum_depth,
75 const bool& use_root_frame,
76 const bool& enable_colors
80 bool valid_rgb =
false;
84 std::tie(valid_rgb, rgb) = this->rgb(blocking);
86 return std::make_pair(
false, MatrixXd());
90 bool valid_depth =
false;
92 std::tie(valid_depth,
depth) = this->
depth(blocking);
94 return std::make_pair(
false, MatrixXd());
98 bool valid_pose =
false;
102 std::tie(valid_pose, camera_pose) = this->pose(blocking);
104 return std::make_pair(
false, MatrixXd());
108 MatrixXi valid_points(parameters_.height(), parameters_.width());
110 for (std::size_t v = 0; v < parameters_.height(); v++)
112 for (std::size_t u = 0; u < parameters_.width(); u++)
114 valid_points(v, u) = 0;
116 float depth_u_v =
depth(v, u);
118 if ((depth_u_v > 0) && (depth_u_v < maximum_depth))
119 valid_points(v, u) = 1;
122 const std::size_t number_valids = valid_points.sum();
124 if (number_valids == 0)
125 return std::make_pair(
false, MatrixXd());
128 bool valid_deprojection_matrix =
false;
131 if (!valid_deprojection_matrix)
132 return std::make_pair(
false, MatrixXd());
135 const std::size_t number_rows = enable_colors ? 6 : 3;
136 MatrixXd cloud(number_rows, number_valids);
137 std::size_t counter = 0;
138 for (std::size_t v = 0; v < parameters_.height(); v++)
139 for (std::size_t u = 0; u < parameters_.width(); u++)
141 if (valid_points(v, u) == 1)
149 cv::Vec3b cv_color = rgb.at<cv::Vec3b>(cv::Point2d(u, v));
150 cloud.col(counter)(3) = cv_color[2];
151 cloud.col(counter)(4) = cv_color[1];
152 cloud.col(counter)(5) = cv_color[0];
160 cloud.topRows<3>() = camera_pose * cloud.topRows<3>().colwise().homogeneous();
162 return std::make_pair(
true, cloud);
166std::pair<bool, double> Camera::time_stamp_rgb()
const
168 return std::make_pair(
false, 0.0);
172std::pair<bool, double> Camera::time_stamp_depth()
const
174 return std::make_pair(
false, 0.0);
180 return std::make_pair(
false, VectorXd());
184std::size_t Camera::auxiliary_data_size()
const
193 return frame_index_ + dataset_parameters_.index_offset();
199bool Camera::is_offline()
const
201 return offline_mode_;
205bool Camera::set_frame_index(
const std::int32_t& index)
207 if (
int(index - dataset_parameters_.index_offset()) < 0)
210 frame_index_ = index - dataset_parameters_.index_offset();
216bool Camera::step_frame()
221 if (is_probe(
"camera_parameters_output"))
222 get_probe(
"camera_parameters_output").set_data(parameters_.
parameters());
224 if (is_probe(
"dataset_parameters_output"))
225 get_probe(
"dataset_parameters_output").set_data(dataset_parameters_.
parameters());
229 if ((frame_index_ + 1) > number_frames_)
244 bool valid_rgb =
false;
246 std::tie(valid_rgb, rgb_image) = rgb(
true);
252 bool valid_depth =
false;
258 bool valid_pose =
false;
260 std::tie(valid_pose, camera_pose) = pose(
true);
265 bool is_aux_data =
false;
270 IOFormat full_precision(FullPrecision);
273 AngleAxisd angle_axis(camera_pose.rotation());
275 angle(0) = angle_axis.angle();
278 cv::imwrite(log_path_ +
"rgb_" + std::to_string(log_index_) +
"." + dataset_parameters_.rgb_format(), rgb_image);
281 log_ << log_index_ <<
" "
282 << camera_pose.translation().transpose().format(full_precision) <<
" "
283 << angle_axis.axis().transpose().format(full_precision) <<
" "
284 << angle.format(full_precision);
287 log_ <<
" " << aux_data.transpose().format(full_precision);
297bool Camera::start_log(
const std::string& path)
300 if (log_path_.back() !=
'/')
303 log_.open(log_path_ +
"data.txt");
307 return log_.is_open();
311bool Camera::stop_log()
319bool Camera::initialize()
329 bool valid_data =
false;
330 std::tie(valid_data, data_) = load_data();
332 throw(std::runtime_error(
log_name_ +
"::initialize. Cannot load offline data from " + dataset_parameters_.path()));
341 if (!parameters_.initialized())
342 throw(std::runtime_error(
log_name_ +
"::reset. Camera parameters not initialized. Did you initialize the class member 'parameters_' in the derived class?."));
345 deprojection_matrix_ = RobotsIO::Camera::deprojection_matrix(parameters_);
347 deprojection_matrix_initialized_ =
true;
355 const std::string& data_path,
356 const std::size_t& width,
357 const std::size_t& height,
366 parameters_.width(width);
367 parameters_.height(height);
372 parameters_.initialized(
true);
375 dataset_parameters_.path(data_path);
378 if (dataset_parameters_.path().back() !=
'/')
379 dataset_parameters_.path(dataset_parameters_.path() +
'/');
382 std::cout <<
log_name_ +
"::ctor. Camera parameters:" << std::endl;
383 std::cout <<
log_name_ +
" - width: " << parameters_.width() << std::endl;
384 std::cout <<
log_name_ +
" - height: " << parameters_.height() << std::endl;
385 std::cout <<
log_name_ +
" - fx: " << parameters_.fx() << std::endl;
386 std::cout <<
log_name_ +
" - fy: " << parameters_.fy() << std::endl;
387 std::cout <<
log_name_ +
" - cx: " << parameters_.cx() << std::endl;
388 std::cout <<
log_name_ +
" - cy: " << parameters_.cy() << std::endl;
395 return std::make_pair(
false, MatrixXf());
397 const std::string file_name = dataset_parameters_.path() + dataset_parameters_.depth_prefix() + compose_index(
frame_index() + depth_offset_) +
"." + dataset_parameters_.depth_format();
399 MatrixXf float_image;
400 bool valid_image =
false;
401 std::tie(valid_image, float_image) = file_to_depth(file_name);
403 return std::make_pair(
false, MatrixXf());
407 bool is_resize =
false;
408 if ((parameters_.width() != 0) && (parameters_.height() != 0))
410 if ((float_image.cols() > parameters_.width()) && (float_image.rows() > parameters_.height()))
412 if ((float_image.cols() % parameters_.width() == 0) && ((float_image.rows() % parameters_.height() == 0)))
414 std::size_t ratio = float_image.cols() / parameters_.width();
415 if (ratio == (float_image.rows() / parameters_.height()))
417 depth.resize(parameters_.height(), parameters_.width());
418 for (std::size_t i = 0; i < float_image.rows(); i += ratio)
419 for (std::size_t j = 0; j < float_image.cols(); j += ratio)
420 depth(i / ratio, j / ratio) = float_image(i, j);
433 cv::eigen2cv(
depth, depth_cv);
434 if (is_probe(
"depth_output"))
435 get_probe(
"depth_output").set_data(depth_cv);
437 return std::make_pair(
true,
depth);
441std::pair<bool, Transform<double, 3, Affine>> Camera::pose_offline()
446 if (dataset_parameters_.data_available())
448 VectorXd data = data_.col(frame_index_);
450 Vector3d position = data.segment<3>(2);
451 VectorXd axis_angle = data.segment<4>(2 + 3);
452 AngleAxisd angle_axis(axis_angle(3), axis_angle.head<3>());
455 pose = Translation<double, 3>(position);
456 pose.rotate(angle_axis);
459 if (is_probe(
"pose_output"))
460 get_probe(
"pose_output").set_data(pose);
462 return std::make_pair(
true, pose);
469std::pair<bool, cv::Mat> Camera::rgb_offline()
472 return std::make_pair(
false, cv::Mat());
474 const std::string file_name = dataset_parameters_.path() + dataset_parameters_.rgb_prefix() + compose_index(
frame_index() + rgb_offset_) +
"." + dataset_parameters_.rgb_format();
475 cv::Mat image = cv::imread(file_name, cv::IMREAD_COLOR);
479 std::cout <<
log_name_ <<
"::rgb_offline. Warning: frame " << file_name <<
" is empty!" << std::endl;
480 return std::make_pair(
false, cv::Mat());
482 if ((parameters_.width() != 0) && (parameters_.height() != 0))
483 cv::resize(image, image, cv::Size(parameters_.width(), parameters_.height()));
486 if (is_probe(
"rgb_output"))
487 get_probe(
"rgb_output").set_data(image);
489 return std::make_pair(
true, image);
493std::pair<bool, double> Camera::time_stamp_rgb_offline()
const
495 if (status() && dataset_parameters_.data_available())
497 VectorXd data = data_.col(frame_index_ + rgb_offset_);
499 return std::make_pair(
true, data(0));
502 return std::make_pair(
false, 0.0);
506std::pair<bool, double> Camera::time_stamp_depth_offline()
const
508 if (status() && dataset_parameters_.data_available())
510 VectorXd data = data_.col(frame_index_ + depth_offset_);
512 return std::make_pair(
true, data(1));
515 return std::make_pair(
false, 0.0);
521 if (status() && dataset_parameters_.data_available())
523 VectorXd data = data_.col(frame_index_);
525 if (auxiliary_data_size() == 0)
526 return std::make_pair(
false, VectorXd());
529 if (is_probe(
"auxiliary_data_output"))
530 get_probe(
"auxiliary_data__output").set_data(data);
532 return std::make_pair(
true, data.segment(dataset_parameters_.standard_data_offset(), auxiliary_data_size()));
535 return std::make_pair(
false, VectorXd());
539std::string Camera::compose_index(
const std::size_t& index)
541 std::ostringstream ss;
542 ss << std::setw(dataset_parameters_.heading_zeros()) << std::setfill(
'0') << index;
547std::pair<bool, MatrixXd> Camera::load_data()
550 const std::string file_name = dataset_parameters_.path() + dataset_parameters_.data_prefix() +
"data." + dataset_parameters_.data_format();
551 const std::size_t num_fields = dataset_parameters_.standard_data_offset() + auxiliary_data_size();
553 std::ifstream istrm(file_name);
554 if (!istrm.is_open())
556 std::cout <<
log_name_ +
"::read_data_from_file. Error: failed to open " << file_name << std::endl;
558 return std::make_pair(
false, MatrixXd(0,0));
561 std::vector<std::string> istrm_strings;
563 while (std::getline(istrm, line))
565 istrm_strings.push_back(line);
568 dataset_parameters_.data_available(
true);
570 data.resize(num_fields, istrm_strings.size());
571 std::size_t found_lines = 0;
572 for (
auto line : istrm_strings)
574 std::size_t found_fields = 0;
575 std::string number_str;
576 std::istringstream iss(line);
578 while (iss >> number_str)
580 if (found_fields > num_fields)
582 std::cout <<
log_name_ +
"::read_data_from_file. Error: malformed input file " << file_name << std::endl;
583 std::cout <<
log_name_ +
"::read_data_from_file. Found more than expected fields. Skipping content parsing." << std::endl;
584 dataset_parameters_.data_available(
false);
585 number_frames_ = data.cols();
586 return std::make_pair(
true, data);
591 std::size_t index = (num_fields * found_lines) + found_fields;
592 *(data.data() + index) = std::stod(number_str);
594 catch (std::invalid_argument)
596 std::cout <<
log_name_ +
"::read_data_from_file. Error: malformed input file " << file_name << std::endl;
597 std::cout <<
log_name_ +
"::read_data_from_file. Found unexpected fields. Skipping content parsing." << std::endl;
598 dataset_parameters_.data_available(
false);
599 number_frames_ = data.cols();
600 return std::make_pair(
true, data);
606 if (found_fields != num_fields)
608 std::cout <<
log_name_ +
"::read_data_from_file. Error: malformed input file " << file_name << std::endl;
609 std::cout <<
log_name_ +
"::read_data_from_file. Found less than expected fields. Skipping content parsing." << std::endl;
610 dataset_parameters_.data_available(
false);
611 number_frames_ = data.cols();
612 return std::make_pair(
true, data);
619 number_frames_ = data.cols();
621 if (dataset_parameters_.data_available())
624 double timestamp_rgb_0 = data.col(0)(0);
625 VectorXd timestamps_depth = data.row(1);
626 VectorXd delta_rgb_depth = (timestamps_depth.array() - timestamp_rgb_0).abs();
627 delta_rgb_depth.minCoeff(&depth_offset_);
629 double timestamp_depth_0 = data.col(0)(1);
630 VectorXd timestamps_rgb = data.row(0);
631 VectorXd delta_depth_rgb = (timestamps_rgb.array() - timestamp_depth_0).abs();
632 delta_depth_rgb.minCoeff(&rgb_offset_);
634 if (depth_offset_ > rgb_offset_)
637 number_frames_ -= depth_offset_;
638 std::cout <<
log_name_ +
"::read_data_from_file. RGB stream is " << depth_offset_ <<
" frames ahead of the depth stream.";
643 number_frames_ -= rgb_offset_;
644 std::cout <<
log_name_ +
"::read_data_from_file. Depth stream is " << rgb_offset_ <<
" frames ahead of the RGB stream.";
647 std::cout <<
" Streams have been re-synchronized." << std::endl;
650 return std::make_pair(
true, data);
virtual std::pair< bool, Eigen::MatrixXd > deprojection_matrix() const
virtual std::pair< bool, Eigen::MatrixXf > depth_offline()
virtual bool evaluate_deprojection_matrix()
virtual bool log_frame(const bool &log_depth=false)
virtual std::int32_t frame_index() const
virtual std::pair< bool, Eigen::VectorXd > auxiliary_data_offline()
const std::string log_name_
virtual std::pair< bool, Eigen::MatrixXf > depth(const bool &blocking)=0
virtual std::pair< bool, Eigen::VectorXd > auxiliary_data(const bool &blocking)
const Parameters * parameters() const