You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
6.6 KiB

// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2021 Intel Corporation. All Rights Reserved.
#include <librealsense2/rs.hpp> // Include RealSense Cross Platform API
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#include "example.hpp"
#include <condition_variable>
#include <librealsense2/hpp/rs_internal.hpp>
#include <librealsense2/hpp/rs_record_playback.hpp>
#include "example-imgui.hpp" // Include short list of convenience functions for rendering
using namespace std;
struct synthetic_frame
{
int x, y, bpp;
std::vector<uint8_t> frame;
};
namespace rs_pointcloud_stitching
{
std::string trim(const std::string& str,
const std::string& whitespace = " \t")
{
const auto strBegin = str.find_first_not_of(whitespace);
if (strBegin == std::string::npos)
return ""; // no content
const auto strEnd = str.find_last_not_of(whitespace);
const auto strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
// Split string into token, trim unreadable characters
inline std::vector<std::string> tokenize(std::string line, char separator)
{
std::vector<std::string> tokens;
// Remove trailing characters
line.erase(line.find_last_not_of("\t\n\v\r ") + 1);
stringstream ss(line);
while (ss.good())
{
string substr;
getline(ss, substr, separator);
tokens.push_back(trim(substr));
}
return tokens;
}
struct stringify
{
std::ostringstream ss;
template<class T> stringify& operator << (const T& val) { ss << val; return *this; }
operator std::string() const { return ss.str(); }
};
inline int parse_number(char const* s, int base = 0)
{
char c;
stringstream ss(s);
int i;
ss >> i;
if (ss.fail() || ss.get(c))
{
throw runtime_error(string(string("Invalid numeric input - ") + s + string("\n")));
}
return i;
}
inline std::string to_lower(const std::string& s)
{
auto copy = s;
std::transform(copy.begin(), copy.end(), copy.begin(), ::tolower);
return copy;
}
inline rs2_format parse_format(const string str)
{
for (int i = RS2_FORMAT_ANY; i < RS2_FORMAT_COUNT; i++)
{
if (to_lower(rs2_format_to_string((rs2_format)i)) == str)
{
return (rs2_format)i;
}
}
throw runtime_error((string("Invalid format - ") + str + string("\n")).c_str());
}
inline rs2_stream parse_stream_type(const string str)
{
for (int i = RS2_STREAM_ANY; i < RS2_STREAM_COUNT; i++)
{
if (to_lower(rs2_stream_to_string((rs2_stream)i)) == str)
{
return static_cast<rs2_stream>(i);
}
}
throw runtime_error((string("Invalid stream type - ") + str + string("\n")).c_str());
}
inline int parse_fps(const string str)
{
return parse_number(str.c_str());
}
struct stream_request
{
rs2_stream _stream_type;
rs2_format _stream_format;
int _width;
int _height;
int _fps;
int _stream_idx;
};
inline std::ostream& operator<<(std::ostream& os, const stream_request& req)
{
return os << "Type: " << req._stream_type << ", Idx: " << req._stream_idx << ", "
<< req._stream_format << ", [" << req._width << "x" << req._height << "], " << req._fps << "fps" << std::endl;
}
enum config_params {
e_stream_type,
e_res_width,
e_res_height,
e_fps,
e_format,
e_stream_index
};
class PipelineSyncer : public rs2::asynchronous_syncer
{
public:
void operator()(rs2::frame f) const
{
invoke(std::move(f));
}
};
class CPointcloudStitcher
{
public:
CPointcloudStitcher(const std::string& working_dir, const std::string& calibration_file);
bool Init();
bool Start();
void Run(window& app);
void StopSensors();
void CloseSensors();
private:
bool GetDevices();
bool OpenSensors(std::shared_ptr<rs2::device> dev);
void frame_callback(rs2::frame frame, const string& serial);
rs2_intrinsics create_intrinsics(const synthetic_frame& _virtual_frame, const float fov_x, const float fov_y); // fov_x, fov_y in radians.
std::map<std::string, double> parse_virtual_device_config_file(const std::string& config_filename);
void InitializeVirtualFrames(const std::map<std::string, double>& virtual_dev_params);
void CreateVirtualDevice();
void ProjectFramesOnOtherDevice(rs2::frameset frames, const string& from_serial, const string& to_serial);
void RecordButton(const ImVec2& window_size);
void SaveFramesButton(const std::map<std::string, rs2::frame>& frames_sets, const ImVec2& window_size);
void DrawTitles(const double fps, const string& value_str, const ImVec2& window_size);
std::string PrintCursorRange(window& app);
void StartRecording(const std::string& path);
void StopRecording();
void SaveOriginImages(const std::map<std::string, rs2::frame>& frames_sets);
void parse_calibration_file(const std::string& config_filename);
private:
std::string _working_dir, _calibration_file;
std::string _left_device;
std::vector<std::shared_ptr<rs2::device> > _devices;
std::map<std::string, std::vector<rs2::sensor> > _active_sensors;
std::map<std::string, std::vector<stream_request> > _wanted_profiles;
std::map<std::string, PipelineSyncer> _syncer;
rs2::syncer _soft_sync;
std::map<std::string, rs2::frame_queue> _frames;
std::mutex _frames_mutex;
std::condition_variable _frame_cv;
frames_mosaic _frames_map;
rs2::pointcloud _pc;
std::map< std::string, std::map<std::string, rs2_extrinsics > > _ir_extrinsics;
rs2::software_device _soft_dev; // Create software-only device
std::string _serial_vir;
synthetic_frame _virtual_depth_frame, _virtual_color_frame;
int _frame_number;
std::shared_ptr<rs2::recorder> _recorder;
bool _is_recording;
rs2::hole_filling_filter _hole_filling_filter;
bool _is_calibrated;
enum frame_id { COLOR1, COLOR_UNITED, COLOR2, DEPTH1, DEPTH_UNITED, DEPTH2};
};
}