camera_related.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 <fmt/chrono.h>
  8. #include <queue>
  9. using namespace simple_mq_singleton;
  10. using namespace sophiar;
  11. struct simple_image_saver {
  12. std::filesystem::path prefix_path;
  13. simple_image_saver() {
  14. prefix_path = fmt::format("./capture_{:%Y_%m_%d_%H_%M_%S}",
  15. now_since_epoch_in_seconds());
  16. std::filesystem::create_directories(prefix_path);
  17. }
  18. void save_image_raw(smart_mat *left, smart_mat *right) const {
  19. auto left_host = left->host();
  20. auto right_host = right->host();
  21. assert(left_host.isContinuous());
  22. assert(right_host.isContinuous());
  23. auto ts_str = fmt::format("{}", system_timestamp());
  24. auto left_name = fmt::format("left_{}.raw", ts_str);
  25. auto right_name = fmt::format("right_{}.raw", ts_str);
  26. auto left_path = prefix_path / left_name;
  27. auto right_path = prefix_path / right_name;
  28. save_file(left_path.c_str(), left_host.data, left_host.total() * left_host.elemSize());
  29. save_file(right_path.c_str(), right_host.data, right_host.total() * right_host.elemSize());
  30. }
  31. private:
  32. static void save_file(const char *file_path, void *data, size_t length) {
  33. static constexpr auto block_size = 512 * 1024; // 512KiB
  34. auto file = fopen(file_path, "wb");
  35. assert(file != nullptr);
  36. auto block_cnt = length / block_size;
  37. auto write_cnt = fwrite(data, block_size, block_cnt, file);
  38. assert(write_cnt == block_cnt);
  39. auto write_len = write_cnt * block_size;
  40. if (length > write_len) {
  41. fwrite((char *) data + write_len, length - write_len, 1, file);
  42. }
  43. fclose(file);
  44. }
  45. };
  46. bool mono_mode = false;
  47. bool enhance_image = false;
  48. bool use_crude_debayer = true; // debug options
  49. bool undistort_image = true; // debug options
  50. int preview_camera_index = 0; // 0 for left, 1 for right
  51. bool save_next_raw = false;
  52. mvs::capture_config capture_conf = {};
  53. stereo_camera_info stereo_info;
  54. std::string left_camera_name, right_camera_name;
  55. std::unique_ptr<mvs::camera> left_camera, right_camera;
  56. std::unique_ptr<simple_image_saver> image_saver;
  57. extern nvenc_config main_nvenc_conf;
  58. extern bool debug_options;
  59. extern float augment_render_angle;
  60. extern float process_frame_rate;
  61. extern local_connection sophiar_conn;
  62. extern std::queue<std::function<void()>> simple_eq;
  63. extern std::unique_ptr<camera_related> left;
  64. extern std::unique_ptr<camera_related> right;
  65. void camera_related::load_intrinsic(YAML::Node conf) {
  66. intrinsic.fx = conf["fx"].as<float>();
  67. intrinsic.fy = conf["fy"].as<float>();
  68. intrinsic.cx = conf["cx"].as<float>();
  69. intrinsic.cy = conf["cy"].as<float>();
  70. intrinsic.k[0] = conf["k0"].as<float>();
  71. intrinsic.k[1] = conf["k1"].as<float>();
  72. intrinsic.width = conf["width"].as<int>();
  73. intrinsic.height = conf["height"].as<int>();
  74. process_conf.camera = &intrinsic;
  75. }
  76. void camera_related::wait_frame(simple_mq::index_type index) const {
  77. uint64_t cur_cnt;
  78. if (auto ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
  79. ptr == nullptr || cur_cnt <= raw_cnt) {
  80. mq().wait_variable(index, raw_cnt);
  81. }
  82. }
  83. void camera_related::process_frame(simple_mq::index_type index) {
  84. uint64_t cur_cnt;
  85. auto raw_ptr = mq().query_variable_ptr<cv::Mat>(index, &cur_cnt);
  86. assert(cur_cnt > raw_cnt);
  87. raw_cnt = cur_cnt;
  88. raw_img = *raw_ptr;
  89. // OpenCV debayer does not support alpha channel
  90. if (undistort_image) {
  91. use_crude_debayer = true;
  92. }
  93. // Undistort is currently not supported in mono mode
  94. if (mono_mode) {
  95. undistort_image = false;
  96. }
  97. // update process config
  98. process_conf.is_mono = mono_mode;
  99. process_conf.crude_debayer = use_crude_debayer;
  100. process_conf.undistort = undistort_image;
  101. process_conf.enhance = enhance_image;
  102. process_conf.resample_height = mq().query_variable<int>(OUTPUT_HEIGHT);
  103. // process image
  104. processor.process(raw_img.dev(stream.cv), &img_dev, process_conf, stream.cv);
  105. // augment render
  106. process_augment();
  107. }
  108. void load_camera_config(YAML::Node conf) {
  109. // load camera names
  110. auto camera_names = conf["names"];
  111. left_camera_name = camera_names["left"].as<std::string>();
  112. right_camera_name = camera_names["right"].as<std::string>();
  113. auto capture_param = conf["capture"];
  114. capture_conf.frame_rate = capture_param["frame_rate"].as<int>();
  115. capture_conf.expo_time_ms = capture_param["expo_time_ms"].as<float>();
  116. capture_conf.gain_db = capture_param["gain_db"].as<float>();
  117. // load camera intrinsics
  118. auto intrinsic_conf = conf["intrinsic"];
  119. left->load_intrinsic(intrinsic_conf["left"]);
  120. right->load_intrinsic(intrinsic_conf["right"]);
  121. // load stereo trans
  122. auto trans_info = conf["stereo_trans"];
  123. stereo_info.transform =
  124. Eigen::Translation3f(
  125. trans_info["tx"].as<float>(),
  126. trans_info["ty"].as<float>(),
  127. trans_info["tz"].as<float>()
  128. ) * Eigen::Quaternionf(
  129. trans_info["qw"].as<float>(),
  130. trans_info["qx"].as<float>(),
  131. trans_info["qy"].as<float>(),
  132. trans_info["qz"].as<float>());
  133. stereo_info.left = &left->intrinsic;
  134. stereo_info.right = &right->intrinsic;
  135. // calculate valid resample range
  136. auto range = calc_valid_range(left->intrinsic, right->intrinsic, &augment_render_angle);
  137. augment_render_angle *= 180 / std::numbers::pi;
  138. left->process_conf.valid_range = range;
  139. right->process_conf.valid_range = range;
  140. }
  141. bool is_camera_opened() {
  142. assert((left_camera == nullptr) == (right_camera == nullptr));
  143. return left_camera != nullptr;
  144. }
  145. bool is_capturing() {
  146. if (!is_camera_opened()) return false;
  147. assert(left_camera->is_capture() == right_camera->is_capture());
  148. return left_camera->is_capture();
  149. }
  150. bool upload_capture_config_impl() {
  151. bool ok = true;
  152. ok &= left_camera->set_capture_config(capture_conf);
  153. ok &= right_camera->set_capture_config(capture_conf);
  154. return ok;
  155. }
  156. void upload_capture_config() {
  157. if (!is_camera_opened()) return;
  158. if (!upload_capture_config_impl()) {
  159. // TODO: show error msg
  160. }
  161. }
  162. void stop_capture() {
  163. left_camera->stop_capture();
  164. right_camera->stop_capture();
  165. }
  166. void start_capture() {
  167. assert(is_camera_opened());
  168. bool ok = true;
  169. ok &= upload_capture_config_impl();
  170. ok &= left_camera->start_capture();
  171. ok &= right_camera->start_capture();
  172. if (!ok) {
  173. // TODO: show error msg
  174. stop_capture();
  175. }
  176. }
  177. void close_cameras() {
  178. if (is_capturing()) {
  179. stop_capture();
  180. }
  181. left_camera.reset();
  182. right_camera.reset();
  183. }
  184. void open_cameras() {
  185. auto pixel_type = mono_mode ? mvs::MONO_8 : mvs::RG_8;
  186. auto left_camera_conf = mvs::create_config{
  187. left_camera_name, pixel_type, IMG_RAW_HOST_LEFT
  188. };
  189. auto right_camera_conf = mvs::create_config{
  190. right_camera_name, pixel_type, IMG_RAW_HOST_RIGHT
  191. };
  192. left_camera.reset(mvs::camera::create(left_camera_conf));
  193. right_camera.reset(mvs::camera::create(right_camera_conf));
  194. if (left_camera == nullptr || right_camera == nullptr) {
  195. // TODO: show error msg
  196. close_cameras();
  197. }
  198. }
  199. void upload_encoder_config();
  200. void wait_camera_frames() {
  201. assert(is_capturing());
  202. left->wait_frame(IMG_RAW_HOST_LEFT);
  203. right->wait_frame(IMG_RAW_HOST_RIGHT);
  204. }
  205. void process_camera_frames() {
  206. left->process_frame(IMG_RAW_HOST_LEFT);
  207. right->process_frame(IMG_RAW_HOST_RIGHT);
  208. // save image if required
  209. if (save_next_raw) {
  210. if (image_saver == nullptr) [[unlikely]] {
  211. image_saver = std::make_unique<simple_image_saver>();
  212. }
  213. image_saver->save_image_raw(&left->raw_img, &right->raw_img);
  214. save_next_raw = false;
  215. }
  216. }
  217. void show_camera_ui() {
  218. // camera actions
  219. ImGui::SeparatorText("Actions");
  220. if (!is_camera_opened()) {
  221. if (ImGui::Button("Open")) {
  222. simple_eq.emplace(open_cameras);
  223. }
  224. } else { // cameras have been opened
  225. if (ImGui::Button("Close")) {
  226. simple_eq.emplace(close_cameras);
  227. }
  228. ImGui::SameLine();
  229. if (!is_capturing()) {
  230. if (ImGui::Button("Start")) {
  231. simple_eq.emplace(start_capture);
  232. }
  233. } else {
  234. if (ImGui::Button("Stop")) {
  235. simple_eq.emplace(stop_capture);
  236. }
  237. ImGui::SameLine();
  238. if (ImGui::Button("Capture Raw")) {
  239. simple_eq.emplace([&] { save_next_raw = true; });
  240. }
  241. }
  242. }
  243. // camera configs
  244. ImGui::SeparatorText("Configs");
  245. if (ImGui::DragInt("Frame Rate (fps)", &capture_conf.frame_rate, 1, 1, 60)) {
  246. simple_eq.emplace(upload_capture_config);
  247. main_nvenc_conf.frame_rate = capture_conf.frame_rate;
  248. simple_eq.emplace(upload_encoder_config);
  249. }
  250. if (ImGui::DragFloat("Exposure Time (ms)", &capture_conf.expo_time_ms,
  251. 0.1, 0.1, 1e3f / capture_conf.frame_rate, "%.01f")) {
  252. simple_eq.emplace(upload_capture_config);
  253. }
  254. if (ImGui::DragFloat("Analog Gain (dB)", &capture_conf.gain_db,
  255. 0.1, 0, 23.4, "%.01f")) {
  256. simple_eq.emplace(upload_capture_config);
  257. }
  258. {
  259. auto guard = imgui_disable_guard{is_camera_opened()};
  260. ImGui::Checkbox("Mono", &mono_mode);
  261. }
  262. ImGui::SameLine();
  263. ImGui::Checkbox("Enhance", &enhance_image);
  264. if (!mono_mode && debug_options) {
  265. ImGui::SameLine();
  266. ImGui::Checkbox("Undistort", &undistort_image);
  267. {
  268. auto guard = imgui_disable_guard{undistort_image};
  269. ImGui::SameLine();
  270. ImGui::Checkbox("Crude Debayer", &use_crude_debayer);
  271. }
  272. }
  273. if (is_capturing()) {
  274. // preview config
  275. ImGui::SeparatorText("Preview Camera");
  276. ImGui::RadioButton("Left", &preview_camera_index, 0);
  277. ImGui::SameLine();
  278. ImGui::RadioButton("Right", &preview_camera_index, 1);
  279. ImGui::SeparatorText("Infos");
  280. {
  281. auto guard = imgui_disable_guard{};
  282. ImGui::DragFloat("Process Frame Rate (fps)", &process_frame_rate, 0, 0, 60, "%.01f");
  283. }
  284. // auto save raw config
  285. // ImGui::SeparatorText("Auto Shoot");
  286. // ImGui::PushID("Auto Shoot");
  287. //
  288. // if (!auto_save_raw) {
  289. // if (ImGui::Button("Start")) {
  290. // auto_save_raw = true;
  291. // }
  292. // } else {
  293. // if (ImGui::Button("Stop")) {
  294. // auto_save_raw = false;
  295. // }
  296. // }
  297. //
  298. // if (auto_save_raw_interval < 1) {
  299. // auto_save_raw_interval = 1;
  300. // }
  301. //
  302. // if (auto_save_raw) {
  303. // ImGui::BeginDisabled();
  304. // auto now_time = std::chrono::system_clock::now();
  305. // if (now_time - last_save_raw_time >
  306. // std::chrono::seconds{auto_save_raw_interval}) {
  307. // camera.request_save_raw();
  308. // last_save_raw_time = now_time;
  309. // }
  310. // }
  311. // ImGui::InputInt("Shoot Interval (s)", &auto_save_raw_interval, 1, 10);
  312. // if (auto_save_raw) {
  313. // ImGui::EndDisabled();
  314. // }
  315. }
  316. }