camera_related.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. #include "core/local_connection.h"
  2. #include "frame_encoder/encoder_nvenc.h"
  3. #include "imgui_utility.h"
  4. #include "impl_types.h"
  5. #include "mvs_camera.h"
  6. #include "variable_defs.h"
  7. #include <opencv2/imgcodecs.hpp>
  8. #include <opencv2/imgproc.hpp>
  9. #include <fmt/chrono.h>
  10. #include <queue>
  11. using namespace simple_mq_singleton;
  12. using namespace sophiar;
  13. struct simple_image_saver {
  14. std::filesystem::path prefix_path;
  15. simple_image_saver() {
  16. prefix_path = fmt::format("./capture_{:%Y_%m_%d_%H_%M_%S}",
  17. now_since_epoch_in_seconds());
  18. std::filesystem::create_directories(prefix_path);
  19. }
  20. void save_image_raw(smart_mat *left, smart_mat *right) const;
  21. void save_image_png(smart_mat *left, smart_mat *right) const;
  22. void save_image_png(const smart_texture &left,
  23. const smart_texture &right) const;
  24. private:
  25. auto get_save_path(std::string_view ext) const {
  26. auto ts_str = fmt::format("{}", system_timestamp());
  27. auto left_name = fmt::format("left_{}.{}", ts_str, ext);
  28. auto right_name = fmt::format("right_{}.{}", ts_str, ext);
  29. auto left_path = prefix_path / left_name;
  30. auto right_path = prefix_path / right_name;
  31. return std::make_tuple(left_path, right_path);
  32. }
  33. static void save_file(const char *file_path, void *data, size_t length) {
  34. static constexpr auto block_size = 512 * 1024; // 512KiB
  35. auto file = fopen(file_path, "wb");
  36. assert(file != nullptr);
  37. auto block_cnt = length / block_size;
  38. auto write_cnt = fwrite(data, block_size, block_cnt, file);
  39. assert(write_cnt == block_cnt);
  40. auto write_len = write_cnt * block_size;
  41. if (length > write_len) {
  42. fwrite((char *) data + write_len, length - write_len, 1, file);
  43. }
  44. fclose(file);
  45. }
  46. static void save_png(const std::string &file_path, const cv::Mat &img) {
  47. cv::Mat out_img = img;
  48. if (out_img.channels() == 3) { // RGB -> BGR
  49. cv::cvtColor(img, out_img, cv::COLOR_RGB2BGR);
  50. }
  51. cv::imwrite(file_path, out_img);
  52. }
  53. static void save_tex(const std::string &file_path, const smart_texture &tex) {
  54. // download texture
  55. GLenum format;
  56. GLsizei width, height;
  57. glBindTexture(GL_TEXTURE_2D, tex.id);
  58. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (int *) &format);
  59. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
  60. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
  61. auto closer = sg::make_scope_guard([&] {
  62. glBindTexture(GL_TEXTURE_2D, 0);
  63. });
  64. switch (format) {
  65. case GL_RGBA8: {
  66. auto img = cv::Mat(height, width, CV_8UC4);
  67. assert(img.isContinuous());
  68. glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_BYTE, img.data);
  69. save_png(file_path, img);
  70. return;
  71. }
  72. default: {
  73. RET_ERROR;
  74. }
  75. }
  76. }
  77. };
  78. void simple_image_saver::save_image_raw(smart_mat *left, smart_mat *right) const {
  79. auto left_host = left->host();
  80. auto right_host = right->host();
  81. assert(left_host.isContinuous());
  82. assert(right_host.isContinuous());
  83. auto [left_path, right_path] = get_save_path(".raw");
  84. save_file(left_path.c_str(), left_host.data, left_host.total() * left_host.elemSize());
  85. save_file(right_path.c_str(), right_host.data, right_host.total() * right_host.elemSize());
  86. }
  87. void simple_image_saver::save_image_png(smart_mat *left, smart_mat *right) const {
  88. auto [left_path, right_path] = get_save_path(".p.png");
  89. save_png(left_path, left->host());
  90. save_png(right_path, right->host());
  91. }
  92. void simple_image_saver::save_image_png(const smart_texture &left,
  93. const smart_texture &right) const {
  94. auto [left_path, right_path] = get_save_path(".t.png");
  95. save_tex(left_path, left);
  96. save_tex(right_path, right);
  97. }
  98. static constexpr auto CAPTURE_RAW_BIT = 1 << 0;
  99. static constexpr auto CAPTURE_PROCESSED_BIT = 1 << 1;
  100. static constexpr auto CAPTURE_AUGMENT_BIT = 1 << 2;
  101. uint8_t capture_flag = 0;
  102. bool capture_raw = false;
  103. bool capture_processed = false;
  104. bool capture_augment = false;
  105. bool mono_mode = true;
  106. bool enhance_image = false;
  107. bool use_crude_debayer = true; // debug options
  108. bool undistort_image = true; // debug options
  109. int preview_camera_index = 0; // 0 for left, 1 for right
  110. mvs::capture_config capture_conf = {};
  111. stereo_camera_info stereo_info;
  112. std::string left_camera_name, right_camera_name;
  113. std::unique_ptr<mvs::camera> left_camera, right_camera;
  114. std::unique_ptr<simple_image_saver> image_saver;
  115. extern nvenc_config main_nvenc_conf;
  116. extern bool debug_options;
  117. extern float augment_render_angle;
  118. extern float process_frame_rate;
  119. extern bool augment_enable;
  120. extern local_connection sophiar_conn;
  121. extern std::queue<std::function<void()>> simple_eq;
  122. extern std::unique_ptr<camera_related> left;
  123. extern std::unique_ptr<camera_related> right;
  124. void camera_related::load_intrinsic(YAML::Node conf) {
  125. intrinsic.fx = conf["fx"].as<float>();
  126. intrinsic.fy = conf["fy"].as<float>();
  127. intrinsic.cx = conf["cx"].as<float>();
  128. intrinsic.cy = conf["cy"].as<float>();
  129. intrinsic.k[0] = conf["k0"].as<float>();
  130. intrinsic.k[1] = conf["k1"].as<float>();
  131. intrinsic.width = conf["width"].as<int>();
  132. intrinsic.height = conf["height"].as<int>();
  133. process_conf.camera = &intrinsic;
  134. }
  135. void camera_related::get_next_frame(simple_mq::index_type index) {
  136. uint64_t cur_cnt;
  137. auto ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
  138. if (ptr == nullptr || cur_cnt <= raw_cnt) {
  139. mq().wait_variable(index, raw_cnt);
  140. ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
  141. assert(cur_cnt > raw_cnt);
  142. }
  143. raw_cnt = cur_cnt;
  144. raw_img = *ptr;
  145. }
  146. void camera_related::process_frame() {
  147. // OpenCV debayer does not support alpha channel
  148. if (undistort_image && !mono_mode) {
  149. use_crude_debayer = true;
  150. }
  151. // update process config
  152. process_conf.is_mono = mono_mode;
  153. process_conf.crude_debayer = use_crude_debayer;
  154. process_conf.undistort = undistort_image;
  155. process_conf.enhance = enhance_image;
  156. process_conf.resample_height = mq().query_variable<int>(OUTPUT_HEIGHT);
  157. // process image
  158. auto img_dev = img_mat.dev(stream.cv);
  159. processor.process(raw_img.dev(stream.cv), &img_dev, process_conf, stream.cv);
  160. img_mat.set_dev_mat(img_dev);
  161. // augment render
  162. process_augment();
  163. }
  164. void load_camera_config(YAML::Node conf) {
  165. // load camera names
  166. auto camera_names = conf["names"];
  167. left_camera_name = camera_names["left"].as<std::string>();
  168. right_camera_name = camera_names["right"].as<std::string>();
  169. auto capture_param = conf["capture"];
  170. capture_conf.frame_rate = capture_param["frame_rate"].as<int>();
  171. capture_conf.expo_time_ms = capture_param["expo_time_ms"].as<float>();
  172. capture_conf.gain_db = capture_param["gain_db"].as<float>();
  173. // load camera intrinsics
  174. auto intrinsic_conf = conf["intrinsic"];
  175. left->load_intrinsic(intrinsic_conf["left"]);
  176. right->load_intrinsic(intrinsic_conf["right"]);
  177. // load stereo trans
  178. auto trans_info = conf["stereo_trans"];
  179. left->transform =
  180. Eigen::Translation3d(
  181. trans_info["tx"].as<double>(),
  182. trans_info["ty"].as<double>(),
  183. trans_info["tz"].as<double>()
  184. ) * Eigen::Quaterniond(
  185. trans_info["qw"].as<double>(),
  186. trans_info["qx"].as<double>(),
  187. trans_info["qy"].as<double>(),
  188. trans_info["qz"].as<double>());
  189. right->transform = Eigen::Isometry3d::Identity();
  190. stereo_info.left = &left->intrinsic;
  191. stereo_info.right = &right->intrinsic;
  192. stereo_info.transform = left->transform.cast<float>();
  193. // calculate valid resample range
  194. auto range = calc_valid_range(left->intrinsic, right->intrinsic, &augment_render_angle);
  195. augment_render_angle *= 180 / std::numbers::pi;
  196. left->process_conf.valid_range = range;
  197. right->process_conf.valid_range = range;
  198. }
  199. bool is_camera_opened() {
  200. assert((left_camera == nullptr) == (right_camera == nullptr));
  201. return left_camera != nullptr;
  202. }
  203. bool is_capturing() {
  204. if (!is_camera_opened()) return false;
  205. assert(left_camera->is_capture() == right_camera->is_capture());
  206. return left_camera->is_capture();
  207. }
  208. bool upload_capture_config_impl() {
  209. bool ok = true;
  210. ok &= left_camera->set_capture_config(capture_conf);
  211. ok &= right_camera->set_capture_config(capture_conf);
  212. return ok;
  213. }
  214. void upload_capture_config() {
  215. if (!is_camera_opened()) return;
  216. if (!upload_capture_config_impl()) {
  217. // TODO: show error msg
  218. }
  219. }
  220. void stop_capture() {
  221. left_camera->stop_capture();
  222. right_camera->stop_capture();
  223. }
  224. void start_capture() {
  225. assert(is_camera_opened());
  226. bool ok = true;
  227. ok &= upload_capture_config_impl();
  228. ok &= left_camera->start_capture();
  229. ok &= right_camera->start_capture();
  230. if (!ok) {
  231. // TODO: show error msg
  232. stop_capture();
  233. }
  234. }
  235. void close_cameras() {
  236. if (is_capturing()) {
  237. stop_capture();
  238. }
  239. left_camera.reset();
  240. right_camera.reset();
  241. }
  242. void open_cameras() {
  243. auto pixel_type = mono_mode ? mvs::MONO_8 : mvs::RG_8;
  244. auto left_camera_conf = mvs::create_config{
  245. left_camera_name, pixel_type, IMG_RAW_HOST_LEFT
  246. };
  247. auto right_camera_conf = mvs::create_config{
  248. right_camera_name, pixel_type, IMG_RAW_HOST_RIGHT
  249. };
  250. left_camera.reset(mvs::camera::create(left_camera_conf));
  251. right_camera.reset(mvs::camera::create(right_camera_conf));
  252. if (left_camera == nullptr || right_camera == nullptr) {
  253. // TODO: show error msg
  254. close_cameras();
  255. }
  256. }
  257. void upload_encoder_config();
  258. void wait_camera_frames() {
  259. assert(is_capturing());
  260. left->get_next_frame(IMG_RAW_HOST_LEFT);
  261. right->get_next_frame(IMG_RAW_HOST_RIGHT);
  262. }
  263. void set_capture_flag() {
  264. capture_flag = 0;
  265. capture_flag |= capture_raw ? CAPTURE_RAW_BIT : 0;
  266. capture_flag |= capture_processed ? CAPTURE_PROCESSED_BIT : 0;
  267. capture_flag |= capture_augment ? CAPTURE_AUGMENT_BIT : 0;
  268. if (image_saver == nullptr) {
  269. image_saver = std::make_unique<simple_image_saver>();
  270. }
  271. }
  272. void process_camera_frames() {
  273. if (capture_flag & CAPTURE_RAW_BIT) {
  274. image_saver->save_image_raw(&left->raw_img, &right->raw_img);
  275. }
  276. left->process_frame();
  277. right->process_frame();
  278. if (capture_flag & CAPTURE_PROCESSED_BIT) {
  279. image_saver->save_image_png(&left->img_mat, &right->img_mat);
  280. }
  281. if (capture_flag & CAPTURE_AUGMENT_BIT) {
  282. image_saver->save_image_png(left->augment_tex, right->augment_tex);
  283. }
  284. // reset capture flag
  285. capture_flag = 0;
  286. }
  287. void show_camera_ui() {
  288. // camera actions
  289. ImGui::SeparatorText("Actions");
  290. if (!is_camera_opened()) {
  291. if (ImGui::Button("Open")) {
  292. simple_eq.emplace(open_cameras);
  293. }
  294. } else { // cameras have been opened
  295. if (ImGui::Button("Close")) {
  296. simple_eq.emplace(close_cameras);
  297. }
  298. ImGui::SameLine();
  299. if (!is_capturing()) {
  300. if (ImGui::Button("Start")) {
  301. simple_eq.emplace(start_capture);
  302. }
  303. } else {
  304. if (ImGui::Button("Stop")) {
  305. simple_eq.emplace(stop_capture);
  306. }
  307. }
  308. }
  309. // camera configs
  310. ImGui::SeparatorText("Configs");
  311. if (ImGui::DragInt("Frame Rate (fps)", &capture_conf.frame_rate, 1, 1, 60)) {
  312. simple_eq.emplace(upload_capture_config);
  313. main_nvenc_conf.frame_rate = capture_conf.frame_rate;
  314. simple_eq.emplace(upload_encoder_config);
  315. }
  316. if (ImGui::DragFloat("Exposure Time (ms)", &capture_conf.expo_time_ms,
  317. 0.1, 0.1, 1e3f / capture_conf.frame_rate, "%.01f")) {
  318. simple_eq.emplace(upload_capture_config);
  319. }
  320. if (ImGui::DragFloat("Analog Gain (dB)", &capture_conf.gain_db,
  321. 0.1, 0, 23.4, "%.01f")) {
  322. simple_eq.emplace(upload_capture_config);
  323. }
  324. {
  325. auto guard = imgui_disable_guard{is_camera_opened()};
  326. ImGui::Checkbox("Mono", &mono_mode);
  327. }
  328. ImGui::SameLine();
  329. ImGui::Checkbox("Enhance", &enhance_image);
  330. if (debug_options) {
  331. ImGui::SameLine();
  332. ImGui::Checkbox("Undistort", &undistort_image);
  333. if (!mono_mode) {
  334. auto guard = imgui_disable_guard{undistort_image};
  335. ImGui::SameLine();
  336. ImGui::Checkbox("Crude Debayer", &use_crude_debayer);
  337. }
  338. }
  339. if (is_capturing()) {
  340. // preview config
  341. ImGui::SeparatorText("Preview Camera");
  342. ImGui::RadioButton("Left", &preview_camera_index, 0);
  343. ImGui::SameLine();
  344. ImGui::RadioButton("Right", &preview_camera_index, 1);
  345. ImGui::SeparatorText("Infos");
  346. {
  347. auto guard = imgui_disable_guard{};
  348. ImGui::DragFloat("Process Frame Rate (fps)", &process_frame_rate, 0, 0, 60, "%.01f");
  349. }
  350. ImGui::SeparatorText("Capture Config");
  351. ImGui::Checkbox("Raw", &capture_raw);
  352. ImGui::SameLine();
  353. ImGui::Checkbox("Processed", &capture_processed);
  354. if (augment_enable) {
  355. ImGui::SameLine();
  356. ImGui::Checkbox("Augment", &capture_augment);
  357. }
  358. ImGui::SameLine();
  359. if (ImGui::Button("Confirm")) {
  360. simple_eq.emplace([&] { set_capture_flag(); });
  361. }
  362. }
  363. }