|
@@ -5,6 +5,9 @@
|
|
|
#include "mvs_camera.h"
|
|
#include "mvs_camera.h"
|
|
|
#include "variable_defs.h"
|
|
#include "variable_defs.h"
|
|
|
|
|
|
|
|
|
|
+#include <opencv2/imgcodecs.hpp>
|
|
|
|
|
+#include <opencv2/imgproc.hpp>
|
|
|
|
|
+
|
|
|
#include <fmt/chrono.h>
|
|
#include <fmt/chrono.h>
|
|
|
|
|
|
|
|
#include <queue>
|
|
#include <queue>
|
|
@@ -21,22 +24,23 @@ struct simple_image_saver {
|
|
|
std::filesystem::create_directories(prefix_path);
|
|
std::filesystem::create_directories(prefix_path);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void save_image_raw(smart_mat *left, smart_mat *right) const {
|
|
|
|
|
- auto left_host = left->host();
|
|
|
|
|
- auto right_host = right->host();
|
|
|
|
|
- assert(left_host.isContinuous());
|
|
|
|
|
- assert(right_host.isContinuous());
|
|
|
|
|
|
|
+ void save_image_raw(smart_mat *left, smart_mat *right) const;
|
|
|
|
|
+
|
|
|
|
|
+ void save_image_png(smart_mat *left, smart_mat *right) const;
|
|
|
|
|
+
|
|
|
|
|
+ void save_image_png(const smart_texture &left,
|
|
|
|
|
+ const smart_texture &right) const;
|
|
|
|
|
|
|
|
|
|
+private:
|
|
|
|
|
+ auto get_save_path(std::string_view ext) const {
|
|
|
auto ts_str = fmt::format("{}", system_timestamp());
|
|
auto ts_str = fmt::format("{}", system_timestamp());
|
|
|
- auto left_name = fmt::format("left_{}.raw", ts_str);
|
|
|
|
|
- auto right_name = fmt::format("right_{}.raw", ts_str);
|
|
|
|
|
|
|
+ auto left_name = fmt::format("left_{}.{}", ts_str, ext);
|
|
|
|
|
+ auto right_name = fmt::format("right_{}.{}", ts_str, ext);
|
|
|
auto left_path = prefix_path / left_name;
|
|
auto left_path = prefix_path / left_name;
|
|
|
auto right_path = prefix_path / right_name;
|
|
auto right_path = prefix_path / right_name;
|
|
|
- save_file(left_path.c_str(), left_host.data, left_host.total() * left_host.elemSize());
|
|
|
|
|
- save_file(right_path.c_str(), right_host.data, right_host.total() * right_host.elemSize());
|
|
|
|
|
|
|
+ return std::make_tuple(left_path, right_path);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-private:
|
|
|
|
|
static void save_file(const char *file_path, void *data, size_t length) {
|
|
static void save_file(const char *file_path, void *data, size_t length) {
|
|
|
static constexpr auto block_size = 512 * 1024; // 512KiB
|
|
static constexpr auto block_size = 512 * 1024; // 512KiB
|
|
|
auto file = fopen(file_path, "wb");
|
|
auto file = fopen(file_path, "wb");
|
|
@@ -50,14 +54,78 @@ private:
|
|
|
}
|
|
}
|
|
|
fclose(file);
|
|
fclose(file);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ static void save_png(const std::string &file_path, const cv::Mat &img) {
|
|
|
|
|
+ cv::Mat out_img = img;
|
|
|
|
|
+ if (out_img.channels() == 3) { // RGB -> BGR
|
|
|
|
|
+ cv::cvtColor(img, out_img, cv::COLOR_RGB2BGR);
|
|
|
|
|
+ }
|
|
|
|
|
+ cv::imwrite(file_path, out_img);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ static void save_tex(const std::string &file_path, const smart_texture &tex) {
|
|
|
|
|
+ // download texture
|
|
|
|
|
+ GLenum format;
|
|
|
|
|
+ GLsizei width, height;
|
|
|
|
|
+ glBindTexture(GL_TEXTURE_2D, tex.id);
|
|
|
|
|
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (int *) &format);
|
|
|
|
|
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
|
|
|
|
|
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
|
|
|
|
|
+ auto closer = sg::make_scope_guard([&] {
|
|
|
|
|
+ glBindTexture(GL_TEXTURE_2D, 0);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ switch (format) {
|
|
|
|
|
+ case GL_RGBA8: {
|
|
|
|
|
+ auto img = cv::Mat(height, width, CV_8UC4);
|
|
|
|
|
+ assert(img.isContinuous());
|
|
|
|
|
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, img.data);
|
|
|
|
|
+ save_png(file_path, img);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ default: {
|
|
|
|
|
+ RET_ERROR;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
-bool mono_mode = false;
|
|
|
|
|
|
|
+void simple_image_saver::save_image_raw(smart_mat *left, smart_mat *right) const {
|
|
|
|
|
+ auto left_host = left->host();
|
|
|
|
|
+ auto right_host = right->host();
|
|
|
|
|
+ assert(left_host.isContinuous());
|
|
|
|
|
+ assert(right_host.isContinuous());
|
|
|
|
|
+ auto [left_path, right_path] = get_save_path(".raw");
|
|
|
|
|
+ save_file(left_path.c_str(), left_host.data, left_host.total() * left_host.elemSize());
|
|
|
|
|
+ save_file(right_path.c_str(), right_host.data, right_host.total() * right_host.elemSize());
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void simple_image_saver::save_image_png(smart_mat *left, smart_mat *right) const {
|
|
|
|
|
+ auto [left_path, right_path] = get_save_path(".p.png");
|
|
|
|
|
+ save_png(left_path, left->host());
|
|
|
|
|
+ save_png(right_path, right->host());
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void simple_image_saver::save_image_png(const smart_texture &left,
|
|
|
|
|
+ const smart_texture &right) const {
|
|
|
|
|
+ auto [left_path, right_path] = get_save_path(".t.png");
|
|
|
|
|
+ save_tex(left_path, left);
|
|
|
|
|
+ save_tex(right_path, right);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static constexpr auto CAPTURE_RAW_BIT = 1 << 0;
|
|
|
|
|
+static constexpr auto CAPTURE_PROCESSED_BIT = 1 << 1;
|
|
|
|
|
+static constexpr auto CAPTURE_AUGMENT_BIT = 1 << 2;
|
|
|
|
|
+uint8_t capture_flag = 0;
|
|
|
|
|
+bool capture_raw = false;
|
|
|
|
|
+bool capture_processed = false;
|
|
|
|
|
+bool capture_augment = false;
|
|
|
|
|
+
|
|
|
|
|
+bool mono_mode = true;
|
|
|
bool enhance_image = false;
|
|
bool enhance_image = false;
|
|
|
bool use_crude_debayer = true; // debug options
|
|
bool use_crude_debayer = true; // debug options
|
|
|
bool undistort_image = true; // debug options
|
|
bool undistort_image = true; // debug options
|
|
|
int preview_camera_index = 0; // 0 for left, 1 for right
|
|
int preview_camera_index = 0; // 0 for left, 1 for right
|
|
|
-bool save_next_raw = false;
|
|
|
|
|
|
|
|
|
|
mvs::capture_config capture_conf = {};
|
|
mvs::capture_config capture_conf = {};
|
|
|
stereo_camera_info stereo_info;
|
|
stereo_camera_info stereo_info;
|
|
@@ -69,6 +137,7 @@ extern nvenc_config main_nvenc_conf;
|
|
|
extern bool debug_options;
|
|
extern bool debug_options;
|
|
|
extern float augment_render_angle;
|
|
extern float augment_render_angle;
|
|
|
extern float process_frame_rate;
|
|
extern float process_frame_rate;
|
|
|
|
|
+extern bool augment_enable;
|
|
|
|
|
|
|
|
extern local_connection sophiar_conn;
|
|
extern local_connection sophiar_conn;
|
|
|
extern std::queue<std::function<void()>> simple_eq;
|
|
extern std::queue<std::function<void()>> simple_eq;
|
|
@@ -89,31 +158,24 @@ void camera_related::load_intrinsic(YAML::Node conf) {
|
|
|
process_conf.camera = &intrinsic;
|
|
process_conf.camera = &intrinsic;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void camera_related::wait_frame(simple_mq::index_type index) const {
|
|
|
|
|
|
|
+void camera_related::get_next_frame(simple_mq::index_type index) {
|
|
|
uint64_t cur_cnt;
|
|
uint64_t cur_cnt;
|
|
|
- if (auto ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
|
|
|
|
|
- ptr == nullptr || cur_cnt <= raw_cnt) {
|
|
|
|
|
|
|
+ auto ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
|
|
|
|
|
+ if (ptr == nullptr || cur_cnt <= raw_cnt) {
|
|
|
mq().wait_variable(index, raw_cnt);
|
|
mq().wait_variable(index, raw_cnt);
|
|
|
|
|
+ ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
|
|
|
|
|
+ assert(cur_cnt > raw_cnt);
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-void camera_related::process_frame(simple_mq::index_type index) {
|
|
|
|
|
- uint64_t cur_cnt;
|
|
|
|
|
- auto raw_ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
|
|
|
|
|
- assert(cur_cnt > raw_cnt);
|
|
|
|
|
raw_cnt = cur_cnt;
|
|
raw_cnt = cur_cnt;
|
|
|
- raw_img = *raw_ptr;
|
|
|
|
|
|
|
+ raw_img = *ptr;
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+void camera_related::process_frame() {
|
|
|
// OpenCV debayer does not support alpha channel
|
|
// OpenCV debayer does not support alpha channel
|
|
|
- if (undistort_image) {
|
|
|
|
|
|
|
+ if (undistort_image && !mono_mode) {
|
|
|
use_crude_debayer = true;
|
|
use_crude_debayer = true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Undistort is currently not supported in mono mode
|
|
|
|
|
- if (mono_mode) {
|
|
|
|
|
- undistort_image = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// update process config
|
|
// update process config
|
|
|
process_conf.is_mono = mono_mode;
|
|
process_conf.is_mono = mono_mode;
|
|
|
process_conf.crude_debayer = use_crude_debayer;
|
|
process_conf.crude_debayer = use_crude_debayer;
|
|
@@ -122,7 +184,9 @@ void camera_related::process_frame(simple_mq::index_type index) {
|
|
|
process_conf.resample_height = mq().query_variable<int>(OUTPUT_HEIGHT);
|
|
process_conf.resample_height = mq().query_variable<int>(OUTPUT_HEIGHT);
|
|
|
|
|
|
|
|
// process image
|
|
// process image
|
|
|
|
|
+ auto img_dev = img_mat.dev(stream.cv);
|
|
|
processor.process(raw_img.dev(stream.cv), &img_dev, process_conf, stream.cv);
|
|
processor.process(raw_img.dev(stream.cv), &img_dev, process_conf, stream.cv);
|
|
|
|
|
+ img_mat.set_dev_mat(img_dev);
|
|
|
|
|
|
|
|
// augment render
|
|
// augment render
|
|
|
process_augment();
|
|
process_augment();
|
|
@@ -146,18 +210,20 @@ void load_camera_config(YAML::Node conf) {
|
|
|
|
|
|
|
|
// load stereo trans
|
|
// load stereo trans
|
|
|
auto trans_info = conf["stereo_trans"];
|
|
auto trans_info = conf["stereo_trans"];
|
|
|
- stereo_info.transform =
|
|
|
|
|
- Eigen::Translation3f(
|
|
|
|
|
- trans_info["tx"].as<float>(),
|
|
|
|
|
- trans_info["ty"].as<float>(),
|
|
|
|
|
- trans_info["tz"].as<float>()
|
|
|
|
|
- ) * Eigen::Quaternionf(
|
|
|
|
|
- trans_info["qw"].as<float>(),
|
|
|
|
|
- trans_info["qx"].as<float>(),
|
|
|
|
|
- trans_info["qy"].as<float>(),
|
|
|
|
|
- trans_info["qz"].as<float>());
|
|
|
|
|
|
|
+ left->transform =
|
|
|
|
|
+ Eigen::Translation3d(
|
|
|
|
|
+ trans_info["tx"].as<double>(),
|
|
|
|
|
+ trans_info["ty"].as<double>(),
|
|
|
|
|
+ trans_info["tz"].as<double>()
|
|
|
|
|
+ ) * Eigen::Quaterniond(
|
|
|
|
|
+ trans_info["qw"].as<double>(),
|
|
|
|
|
+ trans_info["qx"].as<double>(),
|
|
|
|
|
+ trans_info["qy"].as<double>(),
|
|
|
|
|
+ trans_info["qz"].as<double>());
|
|
|
|
|
+ right->transform = Eigen::Isometry3d::Identity();
|
|
|
stereo_info.left = &left->intrinsic;
|
|
stereo_info.left = &left->intrinsic;
|
|
|
stereo_info.right = &right->intrinsic;
|
|
stereo_info.right = &right->intrinsic;
|
|
|
|
|
+ stereo_info.transform = left->transform.cast<float>();
|
|
|
|
|
|
|
|
// calculate valid resample range
|
|
// calculate valid resample range
|
|
|
auto range = calc_valid_range(left->intrinsic, right->intrinsic, &augment_render_angle);
|
|
auto range = calc_valid_range(left->intrinsic, right->intrinsic, &augment_render_angle);
|
|
@@ -236,22 +302,38 @@ void upload_encoder_config();
|
|
|
|
|
|
|
|
void wait_camera_frames() {
|
|
void wait_camera_frames() {
|
|
|
assert(is_capturing());
|
|
assert(is_capturing());
|
|
|
- left->wait_frame(IMG_RAW_HOST_LEFT);
|
|
|
|
|
- right->wait_frame(IMG_RAW_HOST_RIGHT);
|
|
|
|
|
|
|
+ left->get_next_frame(IMG_RAW_HOST_LEFT);
|
|
|
|
|
+ right->get_next_frame(IMG_RAW_HOST_RIGHT);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-void process_camera_frames() {
|
|
|
|
|
- left->process_frame(IMG_RAW_HOST_LEFT);
|
|
|
|
|
- right->process_frame(IMG_RAW_HOST_RIGHT);
|
|
|
|
|
|
|
+void set_capture_flag() {
|
|
|
|
|
+ capture_flag = 0;
|
|
|
|
|
+ capture_flag |= capture_raw ? CAPTURE_RAW_BIT : 0;
|
|
|
|
|
+ capture_flag |= capture_processed ? CAPTURE_PROCESSED_BIT : 0;
|
|
|
|
|
+ capture_flag |= capture_augment ? CAPTURE_AUGMENT_BIT : 0;
|
|
|
|
|
|
|
|
- // save image if required
|
|
|
|
|
- if (save_next_raw) {
|
|
|
|
|
- if (image_saver == nullptr) [[unlikely]] {
|
|
|
|
|
- image_saver = std::make_unique<simple_image_saver>();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (image_saver == nullptr) {
|
|
|
|
|
+ image_saver = std::make_unique<simple_image_saver>();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void process_camera_frames() {
|
|
|
|
|
+ if (capture_flag & CAPTURE_RAW_BIT) {
|
|
|
image_saver->save_image_raw(&left->raw_img, &right->raw_img);
|
|
image_saver->save_image_raw(&left->raw_img, &right->raw_img);
|
|
|
- save_next_raw = false;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ left->process_frame();
|
|
|
|
|
+ right->process_frame();
|
|
|
|
|
+
|
|
|
|
|
+ if (capture_flag & CAPTURE_PROCESSED_BIT) {
|
|
|
|
|
+ image_saver->save_image_png(&left->img_mat, &right->img_mat);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (capture_flag & CAPTURE_AUGMENT_BIT) {
|
|
|
|
|
+ image_saver->save_image_png(left->augment_tex, right->augment_tex);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // reset capture flag
|
|
|
|
|
+ capture_flag = 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void show_camera_ui() {
|
|
void show_camera_ui() {
|
|
@@ -274,10 +356,6 @@ void show_camera_ui() {
|
|
|
if (ImGui::Button("Stop")) {
|
|
if (ImGui::Button("Stop")) {
|
|
|
simple_eq.emplace(stop_capture);
|
|
simple_eq.emplace(stop_capture);
|
|
|
}
|
|
}
|
|
|
- ImGui::SameLine();
|
|
|
|
|
- if (ImGui::Button("Capture Raw")) {
|
|
|
|
|
- simple_eq.emplace([&] { save_next_raw = true; });
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -302,10 +380,10 @@ void show_camera_ui() {
|
|
|
}
|
|
}
|
|
|
ImGui::SameLine();
|
|
ImGui::SameLine();
|
|
|
ImGui::Checkbox("Enhance", &enhance_image);
|
|
ImGui::Checkbox("Enhance", &enhance_image);
|
|
|
- if (!mono_mode && debug_options) {
|
|
|
|
|
|
|
+ if (debug_options) {
|
|
|
ImGui::SameLine();
|
|
ImGui::SameLine();
|
|
|
ImGui::Checkbox("Undistort", &undistort_image);
|
|
ImGui::Checkbox("Undistort", &undistort_image);
|
|
|
- {
|
|
|
|
|
|
|
+ if (!mono_mode) {
|
|
|
auto guard = imgui_disable_guard{undistort_image};
|
|
auto guard = imgui_disable_guard{undistort_image};
|
|
|
ImGui::SameLine();
|
|
ImGui::SameLine();
|
|
|
ImGui::Checkbox("Crude Debayer", &use_crude_debayer);
|
|
ImGui::Checkbox("Crude Debayer", &use_crude_debayer);
|
|
@@ -325,36 +403,17 @@ void show_camera_ui() {
|
|
|
ImGui::DragFloat("Process Frame Rate (fps)", &process_frame_rate, 0, 0, 60, "%.01f");
|
|
ImGui::DragFloat("Process Frame Rate (fps)", &process_frame_rate, 0, 0, 60, "%.01f");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // auto save raw config
|
|
|
|
|
-// ImGui::SeparatorText("Auto Shoot");
|
|
|
|
|
-// ImGui::PushID("Auto Shoot");
|
|
|
|
|
-//
|
|
|
|
|
-// if (!auto_save_raw) {
|
|
|
|
|
-// if (ImGui::Button("Start")) {
|
|
|
|
|
-// auto_save_raw = true;
|
|
|
|
|
-// }
|
|
|
|
|
-// } else {
|
|
|
|
|
-// if (ImGui::Button("Stop")) {
|
|
|
|
|
-// auto_save_raw = false;
|
|
|
|
|
-// }
|
|
|
|
|
-// }
|
|
|
|
|
-//
|
|
|
|
|
-// if (auto_save_raw_interval < 1) {
|
|
|
|
|
-// auto_save_raw_interval = 1;
|
|
|
|
|
-// }
|
|
|
|
|
-//
|
|
|
|
|
-// if (auto_save_raw) {
|
|
|
|
|
-// ImGui::BeginDisabled();
|
|
|
|
|
-// auto now_time = std::chrono::system_clock::now();
|
|
|
|
|
-// if (now_time - last_save_raw_time >
|
|
|
|
|
-// std::chrono::seconds{auto_save_raw_interval}) {
|
|
|
|
|
-// camera.request_save_raw();
|
|
|
|
|
-// last_save_raw_time = now_time;
|
|
|
|
|
-// }
|
|
|
|
|
-// }
|
|
|
|
|
-// ImGui::InputInt("Shoot Interval (s)", &auto_save_raw_interval, 1, 10);
|
|
|
|
|
-// if (auto_save_raw) {
|
|
|
|
|
-// ImGui::EndDisabled();
|
|
|
|
|
-// }
|
|
|
|
|
|
|
+ ImGui::SeparatorText("Capture Config");
|
|
|
|
|
+ ImGui::Checkbox("Raw", &capture_raw);
|
|
|
|
|
+ ImGui::SameLine();
|
|
|
|
|
+ ImGui::Checkbox("Processed", &capture_processed);
|
|
|
|
|
+ if (augment_enable) {
|
|
|
|
|
+ ImGui::SameLine();
|
|
|
|
|
+ ImGui::Checkbox("Augment", &capture_augment);
|
|
|
|
|
+ }
|
|
|
|
|
+ ImGui::SameLine();
|
|
|
|
|
+ if (ImGui::Button("Confirm")) {
|
|
|
|
|
+ simple_eq.emplace([&] { set_capture_flag(); });
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|