File plugin.cpp
File List > ada > server_rx > plugin.cpp
Go to the documentation of this file
#include "plugin.hpp"
#include
using namespace ILLIXR;
using namespace ILLIXR::data_format;
namespace {
[[maybe_unused]] bool write_16_bit_pgm(const cv::Mat& image, const std::string& filename) {
// Check if the input image is 16-bit single-channel
if (image.empty() || image.type() != CV_16U) {
std::cerr << "Input image must be non-empty and 16-bit single-channel." << std::endl;
return false;
}
std::ofstream file(filename, std::ios::binary | std::ios::out);
if (!file.is_open()) {
std::cerr << "Failed to open file: " << filename << std::endl;
return false;
}
// PGM header for a binary P5 type, 16-bit depth
file << "P5\n";
file << image.cols << " " << image.rows << "\n";
file << "65535\n"; // Maximum value for 16-bit depth
// Writing the image data
for (int y = 0; y < image.rows; ++y) {
for (int x = 0; x < image.cols; ++x) {
uint16_t pixelValue = image.at<uint16_t>(y, x);
// Write the pixel value as big endian
char highByte = pixelValue >> 8;
char lowByte = pixelValue & 0xFF;
file.write(&highByte, 1);
file.write(&lowByte, 1);
}
}
file.close();
return true;
}
} // namespace
[[maybe_unused]] server_rx::server_rx(const std::string& name_, phonebook* pb_)
: threadloop{name_, pb_}
, switchboard_{phonebook_->lookup_impl<switchboard>()}
, scannet_{switchboard_->get_writer<scene_recon_type>("ScanNet_Data")}
, ada_reader_{switchboard_->get_buffered_reader<switchboard::event_wrapper<std::string>>("ada_data")} {
if (!std::filesystem::exists(data_path)) {
if (!std::filesystem::create_directory(data_path)) {
spdlog::get("illixr")->error("Failed to create data directory.");
}
}
receive_time.open(data_path + "/server_receive_time.csv");
receive_timestamp.open(data_path + "/server_receiving_timestamp.csv");
receive_size.open(data_path + "/server_receive_size.csv");
if (!receive_time || !receive_timestamp || !receive_size) {
spdlog::get("illixr")->error("[server_rx] Failed to open one or more log files.");
}
/*const int width = 640;
const int height = 480;
msb_buf_.create(height, width, CV_8UC1);
lsb_buf_.create(height, width, CV_8UC1);
hi16_.create(height, width, CV_16U);
lo16_.create(height, width, CV_16U);
depth16_.create(height, width, CV_16U);*/
cur_frame = 0;
const char* env_var_name = "FRAME_COUNT";
const char* env_value = std::getenv(env_var_name);
const char* env_var_name_1 = "FPS";
const char* env_value_1 = std::getenv(env_var_name_1);
if (env_value != nullptr && env_value_1 != nullptr) {
try {
frame_count_ = std::stoul(env_value);
fps_ = std::stoul(env_value_1);
std::cout << "device_tx: Frame Count " << frame_count_ << " FPS " << fps_ << std::endl;
} catch (const std::invalid_argument& e) {
spdlog::get("illixr")->error("Invalid argument: the environment variable is not a valid unsigned integer.");
} catch (const std::out_of_range& e) {
spdlog::get("illixr")->error(
"Out of range: the value of the environment variable is too large for an unsigned integer.");
}
} else {
spdlog::get("illixr")->error("Environment variable not found.");
}
}
void server_rx::_p_one_iteration() {
if (ada_reader_.size() > 0) {
auto buffer_ptr = ada_reader_.dequeue();
std::string buffer_str = **buffer_ptr;
std::string::size_type end_position = buffer_str.find(delimiter);
sr_input_proto::SRSendData sr_input;
bool success = sr_input.ParseFromString(buffer_str.substr(0, end_position));
if (!success) {
spdlog::get("illixr")->error("Error parsing the protobuf, vio input size = {}",
buffer_str.size() - delimiter.size());
} else {
spdlog::get("illixr")->debug("Pose of frame {}: {}, {}, {}; {}, {}, {}, {}", current_frame_no_,
sr_input.input_pose().p_x(), sr_input.input_pose().p_y(), sr_input.input_pose().p_z(),
sr_input.input_pose().o_w(), sr_input.input_pose().o_x(), sr_input.input_pose().o_y(),
sr_input.input_pose().o_z());
receive_sr_input(sr_input);
}
}
}
void server_rx::start() {
decoder_ = std::make_unique<ada_video_decoder>([this](cv::Mat&& img0, cv::Mat&& img1) {
{
std::lock_guard<std::mutex> lock{mutex_};
img0_dst_ = std::move(img0);
img1_dst_ = std::move(img1);
img_ready_ = true;
}
cond_var_.notify_one();
});
decoder_->init();
threadloop::start();
}
void server_rx::receive_sr_input(const sr_input_proto::SRSendData& sr_input) {
#ifndef NDEBUG
spdlog::get("illixr")->debug("Received SR input frame {}/{}", current_frame_no_, frame_count_ - 1);
#endif
auto start = std::chrono::high_resolution_clock::now();
if (cur_frame % fps_ == 0 && cur_frame > 0) {
auto since_epoch = start.time_since_epoch();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(since_epoch).count();
receive_timestamp << cur_frame << " " << millis << "\n";
}
Eigen::Vector3f incoming_position{static_cast<float>(sr_input.input_pose().p_x()),
static_cast<float>(sr_input.input_pose().p_y()),
static_cast<float>(sr_input.input_pose().p_z())};
Eigen::Quaternionf incoming_orientation{
static_cast<float>(sr_input.input_pose().o_w()), static_cast<float>(sr_input.input_pose().o_x()),
static_cast<float>(sr_input.input_pose().o_y()), static_cast<float>(sr_input.input_pose().o_z())};
pose::head_pose_type pose = {time_point{}, incoming_position, incoming_orientation};
// Must do a deep copy of the received data (in the form of a string of bytes)
auto msb = const_cast<std::string&>(sr_input.depth_img_msb_data().img_data());
auto lsb = const_cast<std::string&>(sr_input.depth_img_lsb_data().img_data());
receive_size << "MSB " << cur_frame << " " << sr_input.depth_img_msb_data().size() << "\n";
receive_size << "LSB " << cur_frame << " " << sr_input.depth_img_lsb_data().size() << "\n";
auto depth_decoding_start = std::chrono::high_resolution_clock::now();
std::unique_lock<std::mutex> lock{mutex_};
decoder_->enqueue(msb, lsb);
cond_var_.wait(lock, [this]() {
return img_ready_;
});
img0_dst_.copyTo(msb_buf_);
img1_dst_.copyTo(lsb_buf_);
img_ready_ = false;
lock.unlock();
auto depth_decoding_end = std::chrono::high_resolution_clock::now();
auto duration_depth_decoding =
std::chrono::duration_cast<std::chrono::microseconds>(depth_decoding_end - depth_decoding_start).count();
double duration_depth_decoding_ms = static_cast<double>(duration_depth_decoding) / 1000.0;
// printf("DepthDecode %.3f\n", duration_depth_decoding_ms);
receive_time << "DepthDecode " << cur_frame << " " << duration_depth_decoding_ms << "\n";
auto combine_start = std::chrono::high_resolution_clock::now();
msb_buf_.convertTo(hi16_, CV_16U, 256.0);
lsb_buf_.convertTo(lo16_, CV_16U);
cv::bitwise_or(hi16_, lo16_, depth16_);
auto combine_end = std::chrono::high_resolution_clock::now();
auto duration_combine = std::chrono::duration_cast<std::chrono::microseconds>(combine_end - combine_start).count();
double duration_combine_ms = static_cast<double>(duration_combine) / 1000.0;
receive_time << "Combine " << cur_frame << " " << duration_combine_ms << "\n";
cv::Mat rgb; // pyh dummy here
scannet_.put(scannet_.allocate<scene_recon_type>(scene_recon_type{time_point{}, pose, depth16_.clone(), rgb, false}));
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
auto duration_ms = static_cast<double>(duration) / 1000.0;
receive_time << "Full " << cur_frame << " " << duration_ms << "\n";
cur_frame++;
if (cur_frame == frame_count_) {
receive_time.flush();
receive_size.flush();
receive_timestamp.flush();
}
current_frame_no_++;
}
PLUGIN_MAIN(server_rx)