main_ext.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. #include "components/registration.h"
  2. #include "core/local_connection.h"
  3. #include "cuda_helper.hpp"
  4. #include "experiment/probe_p2p.h"
  5. #include "imgui_utility.h"
  6. #include "main_impl/impl_types.h"
  7. #include "simple_mq.h"
  8. #include "utility.hpp"
  9. #include "variable_defs.h"
  10. #include "vis_marker_detector.h"
  11. #include "vtk_viewer.h"
  12. #ifdef _MSC_VER
  13. #include <format>
  14. #define fmt std
  15. #endif
  16. #include <spdlog/spdlog.h>
  17. #include <yaml-cpp/yaml.h>
  18. #include <glad/gl.h>
  19. #include <GLFW/glfw3.h>
  20. #include <imgui.h>
  21. #include <imgui_impl_glfw.h>
  22. #include <imgui_impl_opengl3.h>
  23. #include <cxxopts.hpp>
  24. #include <boost/iostreams/device/mapped_file.hpp>
  25. #include <cassert>
  26. #include <fstream>
  27. #include <thread>
  28. #include <queue>
  29. #include <vector>
  30. using namespace simple_mq_singleton;
  31. using namespace sophiar;
  32. using boost::iostreams::mapped_file;
  33. std::ofstream main_log_file;
  34. log_timer global_timer;
  35. // global variable definition
  36. CUcontext cuda_ctx = nullptr;
  37. int main_window_width = -1, main_window_height = -1;
  38. GLFWwindow *main_window = nullptr;
  39. float process_frame_rate = 0;
  40. // camera related
  41. extern bool mono_mode;
  42. // render related
  43. extern bool enable_augment_without_nav;
  44. extern std::unique_ptr<scene_render> augment_render;
  45. extern std::vector<augment_store_type> augment_items;
  46. std::string sophiar_config_path;
  47. std::unique_ptr<std::thread> sophiar_thread;
  48. local_connection sophiar_conn;
  49. bool is_tracking = false;
  50. bool enable_reg = false;
  51. std::string probe_model_path;
  52. std::vector<registration_target> reg_targets;
  53. std::unique_ptr<registration> reg;
  54. std::unique_ptr<probe_p2p> exp_probe;
  55. bool debug_options = false;
  56. bool show_vtk_debug = false;
  57. bool show_imgui_demo = false;
  58. std::unique_ptr<vtk_viewer> vtk_test1, vtk_test2;
  59. std::queue<std::function<void()>> simple_eq;
  60. std::queue<std::function<void()>> close_funcs;
  61. std::unique_ptr<camera_related> left;
  62. std::unique_ptr<camera_related> right;
  63. void initialize_render();
  64. void initialize_augment_accuracy();
  65. void initialize_main_window() {
  66. // set GLFW error handler
  67. glfwSetErrorCallback([](int error, const char *desc) {
  68. SPDLOG_ERROR("GLFW error: code = {}, description = {}", error, desc);
  69. });
  70. // create main window
  71. auto ret = glfwInit();
  72. assert(ret == GLFW_TRUE);
  73. glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
  74. glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
  75. glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  76. main_window = glfwCreateWindow(main_window_width, main_window_height,
  77. "RemoteAR V3.-1", nullptr, nullptr);
  78. assert(main_window != nullptr);
  79. glfwMakeContextCurrent(main_window);
  80. glfwSwapInterval(0);
  81. // load opengl functions
  82. auto version = gladLoadGL(glfwGetProcAddress);
  83. assert(version > 0);
  84. SPDLOG_INFO("Loaded OpenGL {}.{}", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
  85. // enable color blending
  86. glEnable(GL_BLEND);
  87. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  88. #ifndef NDEBUG
  89. // log opengl error
  90. glEnable(GL_DEBUG_OUTPUT);
  91. glDebugMessageCallback([](GLenum source, GLenum type, GLuint id, GLenum severity,
  92. GLsizei length, const GLchar *message, const void *user_data) {
  93. if (type == GL_DEBUG_TYPE_ERROR) {
  94. SPDLOG_ERROR("OpenGL error: type = {}, severity = {}, message = {}", type, severity, message);
  95. assert(false);
  96. }
  97. }, nullptr);
  98. #endif
  99. // setup imgui context
  100. IMGUI_CHECKVERSION();
  101. ImGui::CreateContext();
  102. auto io = ImGui::GetIO();
  103. io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
  104. ImGui::StyleColorsDark();
  105. ImGui_ImplGlfw_InitForOpenGL(main_window, true);
  106. ImGui_ImplOpenGL3_Init();
  107. // elegant cleanup
  108. std::atexit([] {
  109. ImGui_ImplOpenGL3_Shutdown();
  110. ImGui_ImplGlfw_Shutdown();
  111. ImGui::DestroyContext();
  112. glfwDestroyWindow(main_window);
  113. glfwTerminate();
  114. });
  115. }
  116. void load_camera_config(YAML::Node conf);
  117. void load_encoder_config(YAML::Node conf);
  118. void load_sender_config(YAML::Node conf);
  119. void load_config(const std::string &config_path) {
  120. auto conf = YAML::LoadFile(config_path);
  121. SPDLOG_INFO("Use config file: {}", config_path);
  122. // initialize mq
  123. mq();
  124. // load module configs
  125. load_camera_config(conf["camera"]);
  126. load_encoder_config(conf["output"]);
  127. load_sender_config(conf["sender"]);
  128. // load render configs
  129. auto opengl_conf = conf["opengl"];
  130. auto shader_dir = opengl_conf["shader_dir"].as<std::string>();
  131. mq().update_variable(SHADER_DIR, shader_dir);
  132. // load main window config
  133. auto window_conf = conf["main_window"];
  134. main_window_width = window_conf["width"].as<int>();
  135. main_window_height = window_conf["height"].as<int>();
  136. // load sophiar config
  137. auto sophiar_conf = conf["sophiar"];
  138. sophiar_config_path = sophiar_conf["config"].as<std::string>();
  139. left->trans_var = sophiar_conf["left_camera_trans_var"].as<std::string>();
  140. right->trans_var = sophiar_conf["right_camera_trans_var"].as<std::string>();
  141. probe_model_path = sophiar_conf["probe_model"].as<std::string>();
  142. // load augment items
  143. for (auto item: sophiar_conf["augment"]) {
  144. auto &store = augment_items.emplace_back();
  145. store.name = item["name"].as<std::string>();
  146. store.trans_var = item["trans_var"].as<std::string>();
  147. store.model_path = item["model_file"].as<std::string>();
  148. if (auto bg_conf = item["background"]; bg_conf) {
  149. store.background = bg_conf.as<std::string>();
  150. } else {
  151. store.background = {};
  152. }
  153. if (auto reg_conf = item["registration"]; reg_conf) {
  154. reg_targets.emplace_back(
  155. store.name, store.model_path,
  156. std::vector<Eigen::Vector3d>{},
  157. reg_conf["target_var"].as<std::string>(),
  158. reg_conf["collect_var"].as<std::string>(),
  159. reg_conf["collect_obj"].as<std::string>(),
  160. reg_conf["probe_var"].as<std::string>());
  161. }
  162. }
  163. // make variables exist
  164. mq().update_variable(SENDER_CONNECTED, false);
  165. mq().update_variable(REQUEST_IDR, false);
  166. mq().update_variable(ENCODER_SHOULD_RESET, false);
  167. }
  168. void initialize_main(int argc, char *argv[]) {
  169. // parse arguments
  170. auto options = cxxopts::Options{"RemoteAR3", "Capture surgery scene and do augmentation works."};
  171. options.add_options()
  172. ("c,config", "Config file", cxxopts::value<std::string>()->default_value("config.yaml"));
  173. auto opts = options.parse(argc, argv);
  174. // initialize cuda
  175. constexpr auto default_cuda_device_id = 0;
  176. cuInit(0);
  177. int cuda_device_count;
  178. CUDA_API_CHECK(cuDeviceGetCount(&cuda_device_count));
  179. assert(cuda_device_count > default_cuda_device_id);
  180. CUdevice cuda_device;
  181. CUDA_API_CHECK(cuDeviceGet(&cuda_device, default_cuda_device_id));
  182. CUDA_API_CHECK(cuCtxCreate(&cuda_ctx, CU_CTX_SCHED_AUTO, cuda_device));
  183. mq().update_variable(CUDA_CONTEXT, cuda_ctx);
  184. std::atexit([] { // elegant cleanup
  185. cuCtxDestroy(cuda_ctx);
  186. });
  187. left = std::make_unique<camera_related>();
  188. right = std::make_unique<camera_related>();
  189. load_config(opts["config"].as<std::string>());
  190. initialize_main_window();
  191. // initialize modules
  192. initialize_render();
  193. initialize_augment_accuracy();
  194. // initialize sophiar
  195. assert(sophiar_thread == nullptr);
  196. sophiar_thread = std::make_unique<std::thread>([=] {
  197. run_sophiar(sophiar_config_path);
  198. });
  199. // initialize components
  200. reg.reset(registration::create({&sophiar_conn,
  201. probe_model_path}));
  202. for (auto &item: reg_targets) {
  203. reg->add_target(item);
  204. }
  205. exp_probe.reset(probe_p2p::create(
  206. {"./models/Probe.stl",
  207. "probe_in_tracker"}));
  208. // initialize vtk test viewer
  209. vtk_test1 = std::make_unique<vtk_viewer>();
  210. vtk_test2 = std::make_unique<vtk_viewer>();
  211. // vtk_test1->clear_actor(); // TODO: remove them
  212. // vtk_test1->add_actor(create_actor("./models/femur.stl"));
  213. // vtk_test1->reset_camera();
  214. // vtk_test2->add_actor(create_actor("./models/tibia.stl"));
  215. // vtk_test1->start_picking();
  216. }
  217. void start_tracking() {
  218. CALL_CHECK(sophiar_conn.start_object("tracker_all"));
  219. is_tracking = true;
  220. }
  221. void close_cameras();
  222. void stop_encoder();
  223. void stop_sender();
  224. void cleanup() {
  225. close_cameras();
  226. stop_encoder();
  227. stop_sender();
  228. // avoid cudaErrorCudartUnloading
  229. left.reset();
  230. right.reset();
  231. // stop sophiar
  232. assert(sophiar_thread != nullptr);
  233. stop_sophiar();
  234. sophiar_thread->join();
  235. sophiar_thread.reset();
  236. // cleanup modules
  237. while (!close_funcs.empty()) {
  238. close_funcs.front()();
  239. close_funcs.pop();
  240. }
  241. }
  242. void show_camera_ui();
  243. void show_encoder_ui();
  244. void show_sender_ui();
  245. void show_augment_ui();
  246. void show_augment_accuracy_ui();
  247. void prepare_imgui_frame() {
  248. glfwPollEvents();
  249. ImGui_ImplOpenGL3_NewFrame();
  250. ImGui_ImplGlfw_NewFrame();
  251. ImGui::NewFrame();
  252. if (show_imgui_demo) {
  253. ImGui::ShowDemoWindow();
  254. }
  255. if (ImGui::Begin("Remote AR Control")) {
  256. ImGui::PushItemWidth(200);
  257. if (ImGui::CollapsingHeader("Camera")) {
  258. ImGui::PushID("Camera");
  259. show_camera_ui();
  260. ImGui::PopID();
  261. }
  262. if (ImGui::CollapsingHeader("Navigation")) {
  263. ImGui::PushID("Encoder");
  264. ImGui::SeparatorText("Actions");
  265. if (ImGui::Button("Start Tracking")) {
  266. simple_eq.emplace(start_tracking);
  267. }
  268. if (is_tracking) {
  269. ImGui::Checkbox("Registration Panel", &enable_reg);
  270. }
  271. ImGui::SeparatorText("Infos");
  272. auto helper_func = [&](const std::string &var_name, const std::string &show_name, bool last = false) {
  273. auto var = sophiar_conn.query_transform_variable(var_name);
  274. bool var_ok = var.has_value();
  275. if (var_ok) {
  276. ImGui::PushStyleColor(ImGuiCol_Text, (ImVec4) ImColor(0, 255, 0));
  277. } else {
  278. ImGui::PushStyleColor(ImGuiCol_Text, (ImVec4) ImColor(255, 0, 0));
  279. }
  280. ImGui::Checkbox(show_name.c_str(), &var_ok);
  281. ImGui::PopStyleColor();
  282. if (!last) {
  283. ImGui::SameLine();
  284. }
  285. };
  286. // ImGui::BeginDisabled();
  287. helper_func("camera_ref_in_tracker", "Camera"); // TODO set in config
  288. helper_func("probe_in_tracker", "Probe");
  289. helper_func("femur_ref_in_tracker", "Femur");
  290. helper_func("tibia_ref_in_tracker", "Tibia", true);
  291. // ImGui::EndDisabled();
  292. ImGui::PopID();
  293. }
  294. if (ImGui::CollapsingHeader("Augment Render")) {
  295. ImGui::PushID("Augment");
  296. show_augment_ui();
  297. ImGui::PopID();
  298. }
  299. if (ImGui::CollapsingHeader("Video Encoder")) {
  300. ImGui::PushID("Encoder");
  301. show_encoder_ui();
  302. ImGui::PopID();
  303. }
  304. if (ImGui::CollapsingHeader("Frame Sender")) {
  305. ImGui::PushID("Sender");
  306. show_sender_ui();
  307. ImGui::PopID();
  308. }
  309. if (ImGui::CollapsingHeader("Debug")) {
  310. ImGui::PushID("Debug");
  311. ImGui::Checkbox("Debug VTK Viewer", &show_vtk_debug);
  312. ImGui::Checkbox("Show ImGui Demo", &show_imgui_demo);
  313. ImGui::Checkbox("Debug Options", &debug_options);
  314. ImGui::Checkbox("Enable Augment without Navigation",
  315. &enable_augment_without_nav);
  316. ImGui::PopID();
  317. }
  318. if (ImGui::CollapsingHeader("Experiment")) {
  319. ImGui::PushID("Experiment");
  320. if (mono_mode) {
  321. if (ImGui::TreeNode("Augment Accuracy")) {
  322. show_augment_accuracy_ui();
  323. ImGui::TreePop();
  324. }
  325. }
  326. if (ImGui::TreeNode("Probe P2P")) {
  327. exp_probe->show_ui();
  328. ImGui::TreePop();
  329. }
  330. ImGui::PopID();
  331. }
  332. ImGui::PopItemWidth();
  333. }
  334. ImGui::End();
  335. if (show_vtk_debug) {
  336. if (ImGui::Begin("VTK Test A", nullptr, vtk_viewer::no_scroll_flag)) {
  337. vtk_test1->show();
  338. }
  339. ImGui::End();
  340. if (ImGui::Begin("VTK Test B", nullptr, vtk_viewer::no_scroll_flag)) {
  341. vtk_test2->show();
  342. }
  343. ImGui::End();
  344. }
  345. if (enable_reg) {
  346. reg->show();
  347. }
  348. ImGui::Render();
  349. }
  350. void process_camera_frames();
  351. void prepare_augment_info();
  352. void process_augment_accuracy();
  353. void process_frame() {
  354. prepare_augment_info();
  355. process_augment_accuracy();
  356. exp_probe->process();
  357. process_camera_frames();
  358. }
  359. void handle_imgui_events() {
  360. while (!simple_eq.empty()) {
  361. simple_eq.front()();
  362. simple_eq.pop();
  363. }
  364. // registration related
  365. if (enable_reg) {
  366. reg->process();
  367. }
  368. }