diff --git a/common/fw-update-helper.cpp b/common/fw-update-helper.cpp index d4ed2c99b2..d13e700c91 100644 --- a/common/fw-update-helper.cpp +++ b/common/fw-update-helper.cpp @@ -38,9 +38,11 @@ namespace rs2 RS2_FWU_STATE_FAILED = 3, }; - bool is_recommended_fw_available() + bool is_recommended_fw_available(std::string id) { - return !(strcmp("", FW_D4XX_FW_IMAGE_VERSION) == 0); + auto pl = parse_product_line(id); + auto fv = get_available_firmware_version(pl); + return !(fv == ""); } int parse_product_line(std::string id) @@ -56,7 +58,7 @@ namespace rs2 if (product_line == RS2_PRODUCT_LINE_D400 && allow_rc_firmware) return FW_D4XX_RC_IMAGE_VERSION; else if (product_line == RS2_PRODUCT_LINE_D400) return FW_D4XX_FW_IMAGE_VERSION; - else if (product_line == RS2_PRODUCT_LINE_SR300) return FW_SR3XX_FW_IMAGE_VERSION; + //else if (product_line == RS2_PRODUCT_LINE_SR300) return FW_SR3XX_FW_IMAGE_VERSION; else return ""; } @@ -437,7 +439,7 @@ namespace rs2 void fw_update_notification_model::draw_expanded(ux_window& win, std::string& error_message) { - if (update_manager->started() && update_state == RS2_FWU_STATE_INITIAL_PROMPT) + if (update_manager->started() && update_state == RS2_FWU_STATE_INITIAL_PROMPT) update_state = RS2_FWU_STATE_IN_PROGRESS; auto flags = ImGuiWindowFlags_NoResize | @@ -548,4 +550,4 @@ namespace rs2 pinned = true; } -} +} \ No newline at end of file diff --git a/common/fw-update-helper.h b/common/fw-update-helper.h index d5e0b06a60..e71f6c8081 100644 --- a/common/fw-update-helper.h +++ b/common/fw-update-helper.h @@ -12,7 +12,7 @@ namespace rs2 std::map> create_default_fw_table(); std::vector parse_fw_version(const std::string& fw); bool is_upgradeable(const std::string& curr, const std::string& available); - bool is_recommended_fw_available(); + bool is_recommended_fw_available(std::string version); class firmware_update_manager : public process_manager { diff --git a/common/model-views.cpp b/common/model-views.cpp index 4377cf05ab..71615ccfe3 100644 --- a/common/model-views.cpp +++ b/common/model-views.cpp @@ -3030,8 +3030,10 @@ namespace rs2 n->snoozed = true; } - viewer.not_model.add_notification(n); - related_notifications.push_back(n); + // NOTE: For now do not pre-emptively suggest auto-calibration + // TODO: Revert in later release + //viewer.not_model.add_notification(n); + //related_notifications.push_back(n); } } } @@ -4326,9 +4328,7 @@ namespace rs2 if (ImGui::IsItemHovered()) ImGui::SetTooltip("Install official signed firmware from file to the device"); - if (is_recommended_fw_available() && - ((dev.supports(RS2_CAMERA_INFO_PRODUCT_LINE)) || - (dev.query_sensors().size() && dev.query_sensors().front().supports(RS2_CAMERA_INFO_PRODUCT_LINE)))) + if (dev.supports(RS2_CAMERA_INFO_PRODUCT_LINE) && is_recommended_fw_available(dev.get_info(RS2_CAMERA_INFO_PRODUCT_LINE))) { if (ImGui::Selectable("Install Recommended Firmware ")) { @@ -4381,13 +4381,11 @@ namespace rs2 viewer.not_model.add_notification(n); n->forced = true; - n->update_state = autocalib_notification_model::RS2_CALIB_STATE_CALIB_IN_PROCESS; + n->update_state = autocalib_notification_model::RS2_CALIB_STATE_SELF_INPUT; for (auto&& n : related_notifications) if (dynamic_cast(n.get())) n->dismiss(false); - - manager->start(n); } catch (const error& e) { diff --git a/common/on-chip-calib.cpp b/common/on-chip-calib.cpp index ee7dbcaf4a..bf63b0b7a2 100644 --- a/common/on-chip-calib.cpp +++ b/common/on-chip-calib.cpp @@ -412,7 +412,7 @@ namespace rs2 log(to_string() << "Warning: " << ex.what()); } - _progress = count * (2 * _speed); + _progress = count * (2 * speed); } while (count++ < 200 && !done); // If we exit due to counter, report timeout @@ -428,86 +428,67 @@ namespace rs2 { std::this_thread::sleep_for(std::chrono::milliseconds(200)); - uint8_t speed = 4 - _speed; + // Begin auto-calibration + std::vector cmd = + { + 0x14, 0x00, 0xab, 0xcd, + 0x80, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, + (uint8_t)speed, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 + }; + + safe_send_command(cmd, "START_CALIB"); + + memset(&result, 0, sizeof(DirectSearchCalibrationResult)); - bool repeat = true; - while (repeat) // Repeat until we got a result + // While not ready... + int count = 0; + bool done = false; + do { - // Begin auto-calibration - std::vector cmd = + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + // Check calibration status + cmd = { 0x14, 0x00, 0xab, 0xcd, 0x80, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, - speed, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - safe_send_command(cmd, "START_CALIB"); - - memset(&result, 0, sizeof(DirectSearchCalibrationResult)); - - // While not ready... - int count = 0; - bool done = false; - do + try { - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - - // Check calibration status - cmd = - { - 0x14, 0x00, 0xab, 0xcd, - 0x80, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 - }; - - try - { - auto res = safe_send_command(cmd, "CALIB_STATUS"); - - if (res.size() < sizeof(int32_t) + sizeof(DirectSearchCalibrationResult)) - throw std::runtime_error("Not enough data from CALIB_STATUS!"); - - result = *reinterpret_cast(res.data()); - done = result.status != RS2_DSC_STATUS_RESULT_NOT_READY; - } - catch (const std::exception& ex) - { - log(to_string() << "Warning: " << ex.what()); - } - - _progress = count * (2 * _speed); + auto res = safe_send_command(cmd, "CALIB_STATUS"); - } while (count++ < 200 && !done); + if (res.size() < sizeof(int32_t) + sizeof(DirectSearchCalibrationResult)) + throw std::runtime_error("Not enough data from CALIB_STATUS!"); - // If we exit due to counter, report timeout - if (!done) + result = *reinterpret_cast(res.data()); + done = result.status != RS2_DSC_STATUS_RESULT_NOT_READY; + } + catch (const std::exception& ex) { - throw std::runtime_error("Operation timed-out!\n" - "Calibration state did not converged in time"); + log(to_string() << "Warning: " << ex.what()); } - std::this_thread::sleep_for(std::chrono::milliseconds(100)); + _progress = count * (2 * speed); - if (result.status != RS2_DSC_STATUS_EDGE_TOO_CLOSE) - { - repeat = false; - } - else - { - // Edge to Close means not enough "samples" to identify fit curve - // Slow down to capture more samples next cycle - log("Edge too close... Slowing down"); - speed++; - if (speed > 4) repeat = false; - } + } while (count++ < 200 && !done); + + // If we exit due to counter, report timeout + if (!done) + { + throw std::runtime_error("Operation timed-out!\n" + "Calibration state did not converged in time"); } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + status = (rs2_dsc_status)result.status; } @@ -543,7 +524,7 @@ namespace rs2 { update_last_used(); - log(to_string() << "Starting calibration at speed " << _speed); + log(to_string() << "Starting calibration at speed " << speed); _in_3d_view = _viewer.is_3d_view; _viewer.is_3d_view = true; @@ -588,6 +569,16 @@ namespace rs2 // Switch into special Auto-Calibration mode start_viewer(256, 144, 90, invoke); + if (speed == 4) // White-wall + { + if (_sub->s->supports(RS2_OPTION_VISUAL_PRESET)) + { + log("Switching into High-Quality preset for White-Wall mode"); + _sub->s->set_option(RS2_OPTION_VISUAL_PRESET, 3.f); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + } + calibrate(); // Get new calibration from the firmware @@ -719,7 +710,8 @@ namespace rs2 if (update_state == RS2_CALIB_STATE_INITIAL_PROMPT) ImGui::Text("%s", "Calibration Health-Check"); else if (update_state == RS2_CALIB_STATE_CALIB_IN_PROCESS || - update_state == RS2_CALIB_STATE_CALIB_COMPLETE) + update_state == RS2_CALIB_STATE_CALIB_COMPLETE || + update_state == RS2_CALIB_STATE_SELF_INPUT) ImGui::Text("%s", "On-Chip Calibration"); else if (update_state == RS2_CALIB_STATE_TARE_INPUT) ImGui::Text("%s", "Tare Calibration"); @@ -839,6 +831,47 @@ namespace rs2 ImGui::SetTooltip("%s", "Begin Tare Calibration"); } } + else if (update_state == RS2_CALIB_STATE_SELF_INPUT) + { + ImGui::SetCursorScreenPos({ float(x + 9), float(y + 33) }); + ImGui::Text("%s", "Speed:"); + + ImGui::SetCursorScreenPos({ float(x + 135), float(y + 30) }); + + std::string id = to_string() << "##speed_" << index; + + std::vector vals{ "Very Fast", "Fast", "Medium", "Slow", "White Wall" }; + std::vector vals_cstr; + for (auto&& s : vals) vals_cstr.push_back(s.c_str()); + + ImGui::PushItemWidth(width - 145); + ImGui::Combo(id.c_str(), &get_manager().speed, vals_cstr.data(), vals.size()); + ImGui::PopItemWidth(); + + auto sat = 1.f + sin(duration_cast(system_clock::now() - created_time).count() / 700.f) * 0.1f; + + ImGui::PushStyleColor(ImGuiCol_Button, saturate(sensor_header_light_blue, sat)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, saturate(sensor_header_light_blue, 1.5f)); + + std::string button_name = to_string() << "Calibrate" << "##self" << index; + + ImGui::SetCursorScreenPos({ float(x + 5), float(y + height - 25) }); + if (ImGui::Button(button_name.c_str(), { float(bar_width), 20.f })) + { + get_manager().restore_workspace([this](std::function a) { a(); }); + get_manager().reset(); + get_manager().start(shared_from_this()); + update_state = RS2_CALIB_STATE_CALIB_IN_PROCESS; + enable_dismiss = false; + } + + ImGui::PopStyleColor(2); + + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip("%s", "Begin On-Chip Calibration"); + } + } else if (update_state == RS2_CALIB_STATE_FAILED) { ImGui::Text("%s", _error_message.c_str()); @@ -871,80 +904,100 @@ namespace rs2 { auto health = get_manager().get_health(); - auto recommend_keep = health > 0.1f; + auto recommend_keep = health > 0.15f; ImGui::SetCursorScreenPos({ float(x + 15), float(y + 33) }); - if (!recommend_keep) ImGui::Text("%s", "Camera original calibration is OK"); - else if (health > 0.2f) ImGui::Text("%s", "We found much better calibration!"); - else ImGui::Text("%s", "We found better calibration for the device!"); - - auto old_fr = get_manager().get_metric(false).first; - auto new_fr = get_manager().get_metric(true).first; + ImGui::Text("Calibration Error: "); - auto old_rms = fabs(get_manager().get_metric(false).second); - auto new_rms = fabs(get_manager().get_metric(true).second); + std::stringstream ss; ss << std::fixed << std::setprecision(2) << health; + auto health_str = ss.str(); - auto fr_improvement = 100.f * ((new_fr - old_fr) / old_fr); - auto rms_improvement = 100.f * ((old_rms - new_rms) / old_rms); - - std::string old_units = "mm"; - if (old_rms > 10.f) + std::string text_name = to_string() << "##notification_text_" << index; + + ImGui::SetCursorScreenPos({ float(x + 136), float(y + 30) }); + ImGui::PushStyleColor(ImGuiCol_Text, white); + ImGui::PushStyleColor(ImGuiCol_FrameBg, transparent); + ImGui::PushStyleColor(ImGuiCol_ScrollbarBg, transparent); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, transparent); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, transparent); + ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, transparent); + ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white); + ImGui::InputTextMultiline(text_name.c_str(), const_cast(health_str.c_str()), + strlen(health_str.c_str()) + 1, { 50, + ImGui::GetTextLineHeight() + 6 }, + ImGuiInputTextFlags_ReadOnly); + ImGui::PopStyleColor(7); + + ImGui::SetCursorScreenPos({ float(x + 172), float(y + 33) }); + + if (!recommend_keep) + { + ImGui::PushStyleColor(ImGuiCol_Text, light_blue); + ImGui::Text("(Good)"); + } + else if (health < 0.25f) { - old_rms /= 10.f; - old_units = "cm"; + ImGui::PushStyleColor(ImGuiCol_Text, yellowish); + ImGui::Text("(Can be Improved)"); } - std::string new_units = "mm"; - if (new_rms > 10.f) + else { - new_rms /= 10.f; - new_units = "cm"; + ImGui::PushStyleColor(ImGuiCol_Text, redish); + ImGui::Text("(Requires Calibration)"); } + ImGui::PopStyleColor(); - if (fr_improvement > 1.f || rms_improvement > 1.f) + if (ImGui::IsItemHovered()) { - std::string txt = to_string() << " Fill-Rate: " << std::setprecision(1) << std::fixed << new_fr << "%%"; + ImGui::SetTooltip("%s", "Calibration error captures how far camera calibration is from the optimal one\n" + "[0, 0.15) - Good\n" + "[0.15, 0.25) - Can be Improved\n" + "[0.25, ) - Requires Calibration"); + } - if (!use_new_calib) - { - txt = to_string() << " Fill-Rate: " << std::setprecision(1) << std::fixed << old_fr << "%%\n"; - } + if (recommend_keep) + { + + auto old_fr = get_manager().get_metric(false).first; + auto new_fr = get_manager().get_metric(true).first; - ImGui::SetCursorScreenPos({ float(x + 12), float(y + 90) }); - ImGui::PushFont(win.get_large_font()); - ImGui::Text("%s", static_cast(textual_icons::check)); - ImGui::PopFont(); + auto old_rms = fabs(get_manager().get_metric(false).second); + auto new_rms = fabs(get_manager().get_metric(true).second); - ImGui::SetCursorScreenPos({ float(x + 35), float(y + 92) }); - ImGui::Text("%s", txt.c_str()); + auto fr_improvement = 100.f * ((new_fr - old_fr) / old_fr); + auto rms_improvement = 100.f * ((old_rms - new_rms) / old_rms); - if (use_new_calib) + std::string old_units = "mm"; + if (old_rms > 10.f) { - ImGui::SameLine(); - - ImGui::PushStyleColor(ImGuiCol_Text, white); - txt = to_string() << " ( +" << std::fixed << std::setprecision(0) << fr_improvement << "%% )"; - ImGui::Text("%s", txt.c_str()); - ImGui::PopStyleColor(); + old_rms /= 10.f; + old_units = "cm"; + } + std::string new_units = "mm"; + if (new_rms > 10.f) + { + new_rms /= 10.f; + new_units = "cm"; } - if (rms_improvement > 1.f) + // NOTE: Disabling metrics temporarily + // TODO: Re-enable in future release + if (/* fr_improvement > 1.f || rms_improvement > 1.f */ false) { - if (use_new_calib) - { - txt = to_string() << " Noise Estimate: " << std::setprecision(2) << std::fixed << new_rms << new_units; - } - else + std::string txt = to_string() << " Fill-Rate: " << std::setprecision(1) << std::fixed << new_fr << "%%"; + + if (!use_new_calib) { - txt = to_string() << " Noise Estimate: " << std::setprecision(2) << std::fixed << old_rms << old_units; + txt = to_string() << " Fill-Rate: " << std::setprecision(1) << std::fixed << old_fr << "%%\n"; } - ImGui::SetCursorScreenPos({ float(x + 12), float(y + 90 + ImGui::GetTextLineHeight() + 6) }); + ImGui::SetCursorScreenPos({ float(x + 12), float(y + 90) }); ImGui::PushFont(win.get_large_font()); ImGui::Text("%s", static_cast(textual_icons::check)); ImGui::PopFont(); - ImGui::SetCursorScreenPos({ float(x + 35), float(y + 92 + ImGui::GetTextLineHeight() + 6) }); + ImGui::SetCursorScreenPos({ float(x + 35), float(y + 92) }); ImGui::Text("%s", txt.c_str()); if (use_new_calib) @@ -952,65 +1005,93 @@ namespace rs2 ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Text, white); - txt = to_string() << " ( -" << std::setprecision(0) << std::fixed << rms_improvement << "%% )"; + txt = to_string() << " ( +" << std::fixed << std::setprecision(0) << fr_improvement << "%% )"; ImGui::Text("%s", txt.c_str()); ImGui::PopStyleColor(); } + + if (rms_improvement > 1.f) + { + if (use_new_calib) + { + txt = to_string() << " Noise Estimate: " << std::setprecision(2) << std::fixed << new_rms << new_units; + } + else + { + txt = to_string() << " Noise Estimate: " << std::setprecision(2) << std::fixed << old_rms << old_units; + } + + ImGui::SetCursorScreenPos({ float(x + 12), float(y + 90 + ImGui::GetTextLineHeight() + 6) }); + ImGui::PushFont(win.get_large_font()); + ImGui::Text("%s", static_cast(textual_icons::check)); + ImGui::PopFont(); + + ImGui::SetCursorScreenPos({ float(x + 35), float(y + 92 + ImGui::GetTextLineHeight() + 6) }); + ImGui::Text("%s", txt.c_str()); + + if (use_new_calib) + { + ImGui::SameLine(); + + ImGui::PushStyleColor(ImGuiCol_Text, white); + txt = to_string() << " ( -" << std::setprecision(0) << std::fixed << rms_improvement << "%% )"; + ImGui::Text("%s", txt.c_str()); + ImGui::PopStyleColor(); + } + } + } + else + { + ImGui::SetCursorScreenPos({ float(x + 12), float(y + 100) }); + ImGui::Text("%s", "Please compare new vs old calibration\nand decide if to keep or discard the result..."); } - } - else - { - ImGui::SetCursorScreenPos({ float(x + 12), float(y + 100) }); - ImGui::Text("%s", "Please compare new vs old calibration\nand decide if to keep or discard the result..."); - } - ImGui::SetCursorScreenPos({ float(x + 9), float(y + 60) }); + ImGui::SetCursorScreenPos({ float(x + 9), float(y + 60) }); - if (ImGui::RadioButton("New", use_new_calib)) - { - use_new_calib = true; - get_manager().apply_calib(true); - } + if (ImGui::RadioButton("New", use_new_calib)) + { + use_new_calib = true; + get_manager().apply_calib(true); + } - ImGui::SetCursorScreenPos({ float(x + 150), float(y + 60) }); - if (ImGui::RadioButton("Original", !use_new_calib)) - { - use_new_calib = false; - get_manager().apply_calib(false); - } + ImGui::SetCursorScreenPos({ float(x + 150), float(y + 60) }); + if (ImGui::RadioButton("Original", !use_new_calib)) + { + use_new_calib = false; + get_manager().apply_calib(false); + } - auto sat = 1.f + sin(duration_cast(system_clock::now() - created_time).count() / 700.f) * 0.1f; + auto sat = 1.f + sin(duration_cast(system_clock::now() - created_time).count() / 700.f) * 0.1f; - if (recommend_keep) - { + ImGui::PushStyleColor(ImGuiCol_Button, saturate(sensor_header_light_blue, sat)); ImGui::PushStyleColor(ImGuiCol_ButtonHovered, saturate(sensor_header_light_blue, 1.5f)); - } - std::string button_name = to_string() << "Apply New" << "##apply" << index; - if (!use_new_calib) button_name = to_string() << "Keep Original" << "##original" << index; + std::string button_name = to_string() << "Apply New" << "##apply" << index; + if (!use_new_calib) button_name = to_string() << "Keep Original" << "##original" << index; - ImGui::SetCursorScreenPos({ float(x + 5), float(y + height - 25) }); - if (ImGui::Button(button_name.c_str(), { float(bar_width), 20.f })) - { - if (use_new_calib) + ImGui::SetCursorScreenPos({ float(x + 5), float(y + height - 25) }); + if (ImGui::Button(button_name.c_str(), { float(bar_width), 20.f })) { - get_manager().keep(); - update_state = RS2_CALIB_STATE_COMPLETE; - pinned = false; - enable_dismiss = false; - last_progress_time = last_interacted = system_clock::now() + milliseconds(500); - } - else dismiss(false); + if (use_new_calib) + { + get_manager().keep(); + update_state = RS2_CALIB_STATE_COMPLETE; + pinned = false; + enable_dismiss = false; + last_progress_time = last_interacted = system_clock::now() + milliseconds(500); + } + else dismiss(false); - get_manager().restore_workspace([this](std::function a){ a(); }); - } + get_manager().restore_workspace([this](std::function a) { a(); }); + } - if (recommend_keep) ImGui::PopStyleColor(2); + ImGui::PopStyleColor(2); - if (ImGui::IsItemHovered()) - { - ImGui::SetTooltip("%s", "New calibration values will be saved in device memory"); + if (ImGui::IsItemHovered()) + { + ImGui::SetTooltip("%s", "New calibration values will be saved in device memory"); + } } } @@ -1188,7 +1269,12 @@ namespace rs2 { if (update_state == RS2_CALIB_STATE_COMPLETE) return 65; else if (update_state == RS2_CALIB_STATE_INITIAL_PROMPT) return 120; - else if (update_state == RS2_CALIB_STATE_CALIB_COMPLETE) return 170; + else if (update_state == RS2_CALIB_STATE_CALIB_COMPLETE) + { + if (get_manager().get_health() > 0.15f) return 170; + else return 80; + } + else if (update_state == RS2_CALIB_STATE_SELF_INPUT) return 85; else if (update_state == RS2_CALIB_STATE_TARE_INPUT) return 160; else return 100; } diff --git a/common/on-chip-calib.h b/common/on-chip-calib.h index 19be61754e..2020ca938b 100644 --- a/common/on-chip-calib.h +++ b/common/on-chip-calib.h @@ -31,10 +31,6 @@ namespace rs2 // Get health number from the calibration summary float get_health() const { return _health; } - // Set calibration speed: 0 - slowest, 4 - fastest - // On-Chip Calib manager will reduce speed if needed - void set_speed(int speed) { _speed = speed; } - // Write new calibration to the device void keep(); @@ -53,6 +49,7 @@ namespace rs2 int average_step_count = 20; int step_count = 20; int accuracy = 2; + int speed = 3; bool tare = false; void calibrate(); @@ -68,7 +65,6 @@ namespace rs2 void process_flow(std::function cleanup, invoker invoke) override; float _health = 0.f; - int _speed = 4; device _dev; bool _was_streaming = false; @@ -101,6 +97,7 @@ namespace rs2 RS2_CALIB_STATE_CALIB_IN_PROCESS,// Calibration in process... Shows progressbar RS2_CALIB_STATE_CALIB_COMPLETE, // Calibration complete, show before/after toggle and metrics RS2_CALIB_STATE_TARE_INPUT, // Collect input parameters for Tare calib + RS2_CALIB_STATE_SELF_INPUT, // Collect input parameters for Self calib }; autocalib_notification_model(std::string name, diff --git a/common/viewer.cpp b/common/viewer.cpp index ec6834a995..cee47a57d1 100644 --- a/common/viewer.cpp +++ b/common/viewer.cpp @@ -1684,11 +1684,7 @@ namespace rs2 ImGui::PushFont(window.get_large_font()); ImGui::PushStyleColor(ImGuiCol_Border, black); - int buttons = window.is_fullscreen() ? 5 : 4; - - ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 2)); - not_model.draw_snoozed_button(); - ImGui::SameLine(); + int buttons = window.is_fullscreen() ? 4 : 3; ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons)); ImGui::PushStyleColor(ImGuiCol_Text, is_3d_view ? light_grey : light_blue); @@ -1716,7 +1712,7 @@ namespace rs2 ImGui::PopStyleColor(2); ImGui::SameLine(); - ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 3)); + ImGui::SetCursorPosX(window.width() - panel_width - panel_y * (buttons - 2)); static bool settings_open = false; ImGui::PushStyleColor(ImGuiCol_Text, !settings_open ? light_grey : light_blue); diff --git a/include/librealsense2/hpp/rs_export.hpp b/include/librealsense2/hpp/rs_export.hpp index ce7a6bfe98..127c4e20b5 100644 --- a/include/librealsense2/hpp/rs_export.hpp +++ b/include/librealsense2/hpp/rs_export.hpp @@ -170,34 +170,55 @@ namespace rs2 software_device dev; std::vector> sensors; + std::vector> extrinsics; + if (auto fs = data.as()) { - int uid = 0; for (int i = 0; i < fs.size(); ++i) { frame f = fs[i]; auto profile = f.get_profile(); std::stringstream sname; - sname << "Sensor (" << uid << ")"; + sname << "Sensor (" << i << ")"; auto s = dev.add_sensor(sname.str()); stream_profile software_profile; if (auto vf = f.as()) { auto vp = profile.as(); - rs2_video_stream stream{ vp.stream_type(), vp.stream_index(), uid++, vp.width(), vp.height(), vp.fps(), vf.get_bytes_per_pixel(), vp.format(), vp.get_intrinsics() }; + rs2_video_stream stream{ vp.stream_type(), vp.stream_index(), i, vp.width(), vp.height(), vp.fps(), vf.get_bytes_per_pixel(), vp.format(), vp.get_intrinsics() }; software_profile = s.add_video_stream(stream); + if (f.is()) { + auto ds = sensor_from_frame(f)->as(); + s.add_read_only_option(RS2_OPTION_DEPTH_UNITS, ds.get_option(RS2_OPTION_DEPTH_UNITS)); + } } else if (f.is()) { auto mp = profile.as(); - rs2_motion_stream stream{ mp.stream_type(), mp.stream_index(), uid++, mp.fps(), mp.format(), mp.get_motion_intrinsics() }; + rs2_motion_stream stream{ mp.stream_type(), mp.stream_index(), i, mp.fps(), mp.format(), mp.get_motion_intrinsics() }; software_profile = s.add_motion_stream(stream); } else if (f.is()) { - rs2_pose_stream stream{ profile.stream_type(), profile.stream_index(), uid++, profile.fps(), profile.format() }; + rs2_pose_stream stream{ profile.stream_type(), profile.stream_index(), i, profile.fps(), profile.format() }; software_profile = s.add_pose_stream(stream); } else { // TODO: How to handle other frame types? (e.g. points) assert(false); } sensors.emplace_back(s, software_profile, i); + + bool found_extrin = false; + for (auto& root : extrinsics) { + try { + std::get<0>(root).register_extrinsics_to(software_profile, + std::get<1>(root).get_extrinsics_to(profile) + ); + found_extrin = true; + break; + } catch (...) {} + } + if (!found_extrin) { + extrinsics.emplace_back(software_profile, profile); + } } + + // Recorder needs sensors to already exist when its created std::stringstream name; name << fname << data.get_frame_number() << ".bag"; @@ -219,6 +240,8 @@ namespace rs2 s.on_pose_frame({ const_cast(f.get_data()), [](void*) {}, f.get_timestamp(), f.get_frame_timestamp_domain(), static_cast(f.get_frame_number()), profile }); } + s.stop(); + s.close(); } } else { // single frame diff --git a/include/librealsense2/hpp/rs_processing.hpp b/include/librealsense2/hpp/rs_processing.hpp index 8accfa0621..e2831c2518 100644 --- a/include/librealsense2/hpp/rs_processing.hpp +++ b/include/librealsense2/hpp/rs_processing.hpp @@ -119,8 +119,9 @@ namespace rs2 * create frame queue. frame queues are the simplest x-platform synchronization primitive provided by librealsense * to help developers who are not using async APIs * param[in] capacity size of the frame queue + * param[in] keep_frames if set to true, the queue automatically calls keep() on every frame enqueued into it. */ - explicit frame_queue(unsigned int capacity) : _capacity(capacity) + explicit frame_queue(unsigned int capacity, bool keep_frames = false) : _capacity(capacity), _keep(keep_frames) { rs2_error* e = nullptr; _queue = std::shared_ptr( @@ -137,6 +138,7 @@ namespace rs2 */ void enqueue(frame f) const { + if (_keep) f.keep(); rs2_enqueue_frame(f.frame_ref, _queue.get()); // noexcept f.frame_ref = nullptr; // frame has been essentially moved from } @@ -194,9 +196,16 @@ namespace rs2 */ size_t capacity() const { return _capacity; } + /** + * Return whether or not the queue calls keep on enqueued frames + * \return keeping frames + */ + bool keep_frames() const { return _keep; } + private: std::shared_ptr _queue; size_t _capacity; + bool _keep; }; /** diff --git a/include/librealsense2/rs.h b/include/librealsense2/rs.h index 461e2120c5..0b172c6949 100644 --- a/include/librealsense2/rs.h +++ b/include/librealsense2/rs.h @@ -24,7 +24,7 @@ extern "C" { #define RS2_API_MAJOR_VERSION 2 #define RS2_API_MINOR_VERSION 28 -#define RS2_API_PATCH_VERSION 0 +#define RS2_API_PATCH_VERSION 1 #define RS2_API_BUILD_VERSION 0 #ifndef STRINGIFY diff --git a/package.xml b/package.xml index 09e2eed6f5..6e42c46b83 100644 --- a/package.xml +++ b/package.xml @@ -7,7 +7,7 @@ librealsense2 - 2.28.0 + 2.28.1 Library for capturing data from the Intel(R) RealSense(TM) SR300, D400 Depth cameras and T2xx Tracking devices. This effort was initiated to better support researchers, creative coders, and app developers in domains such as robotics, virtual reality, and the internet of things. Several often-requested features of RealSense(TM); devices are implemented in this project. diff --git a/src/android/jni/sensor.cpp b/src/android/jni/sensor.cpp index 6e227e7eee..baeb668463 100644 --- a/src/android/jni/sensor.cpp +++ b/src/android/jni/sensor.cpp @@ -40,3 +40,39 @@ Java_com_intel_realsense_librealsense_Sensor_nGetStreamProfiles(JNIEnv *env, jcl env->SetLongArrayRegion(rv, 0, profiles.size(), reinterpret_cast(profiles.data())); return rv; } + +extern "C" +JNIEXPORT void JNICALL +Java_com_intel_realsense_librealsense_RoiSensor_nSetRegionOfInterest(JNIEnv *env, jclass clazz, + jlong handle, jint min_x, + jint min_y, jint max_x, + jint max_y) { + rs2_error* e = nullptr; + rs2_set_region_of_interest(reinterpret_cast(handle), min_x, min_y, max_x, max_y, &e); + handle_error(env, e); +} + +extern "C" +JNIEXPORT void JNICALL +Java_com_intel_realsense_librealsense_RoiSensor_nGetRegionOfInterest(JNIEnv *env, jclass type, + jlong handle, jobject roi) { + int min_x, min_y, max_x, max_y; + rs2_error *e = nullptr; + rs2_get_region_of_interest(reinterpret_cast(handle), &min_x, &min_y, &max_x, &max_y, &e); + handle_error(env, e); + + if(e) + return; + + jclass clazz = env->GetObjectClass(roi); + + jfieldID min_x_field = env->GetFieldID(clazz, "minX", "I"); + jfieldID min_y_field = env->GetFieldID(clazz, "minY", "I"); + jfieldID max_x_field = env->GetFieldID(clazz, "maxX", "I"); + jfieldID max_y_field = env->GetFieldID(clazz, "maxY", "I"); + + env->SetIntField(roi, min_x_field, min_x); + env->SetIntField(roi, min_y_field, min_y); + env->SetIntField(roi, max_x_field, max_x); + env->SetIntField(roi, max_y_field, max_y); +} \ No newline at end of file diff --git a/src/ds5/ds5-color.cpp b/src/ds5/ds5-color.cpp index 3618183dd6..b7ad1cc7fd 100644 --- a/src/ds5/ds5-color.cpp +++ b/src/ds5/ds5-color.cpp @@ -74,6 +74,11 @@ namespace librealsense color_ep->register_pu(RS2_OPTION_BACKLIGHT_COMPENSATION); color_ep->register_pu(RS2_OPTION_AUTO_EXPOSURE_PRIORITY); } + // From 5.11.15 auto-exposure priority is supported on the D465 + else if (_fw_version >= firmware_version("5.11.15.0")) + { + color_ep->register_pu(RS2_OPTION_AUTO_EXPOSURE_PRIORITY); + } if (color_devices_info.front().pid == ds::RS465_PID) color_ep->register_pixel_format(pf_mjpg); diff --git a/src/ivcam/sr300.cpp b/src/ivcam/sr300.cpp index 9a55c09a05..b1f2fddfd5 100644 --- a/src/ivcam/sr300.cpp +++ b/src/ivcam/sr300.cpp @@ -281,7 +281,7 @@ namespace librealsense enable_timestamp(true, true); auto pid_hex_str = hexify(color.pid); - auto recommended_fw_version = firmware_version(SR3XX_RECOMMENDED_FIRMWARE_VERSION); + //auto recommended_fw_version = firmware_version(SR3XX_RECOMMENDED_FIRMWARE_VERSION); register_info(RS2_CAMERA_INFO_NAME, device_name); register_info(RS2_CAMERA_INFO_SERIAL_NUMBER, serial); @@ -292,7 +292,7 @@ namespace librealsense register_info(RS2_CAMERA_INFO_PRODUCT_ID, pid_hex_str); register_info(RS2_CAMERA_INFO_PRODUCT_LINE, "SR300"); register_info(RS2_CAMERA_INFO_CAMERA_LOCKED, _is_locked ? "YES" : "NO"); - register_info(RS2_CAMERA_INFO_RECOMMENDED_FIRMWARE_VERSION, recommended_fw_version); + //register_info(RS2_CAMERA_INFO_RECOMMENDED_FIRMWARE_VERSION, recommended_fw_version); register_autorange_options(); diff --git a/src/l500/l500-color.h b/src/l500/l500-color.h index 26204309ca..4977d1f5db 100644 --- a/src/l500/l500-color.h +++ b/src/l500/l500-color.h @@ -67,6 +67,18 @@ namespace librealsense intrinsics.fy = model.ipm.focal_length.y; intrinsics.ppx = model.ipm.principal_point.x; intrinsics.ppy = model.ipm.principal_point.y; + + if (model.distort.radial_k1 || model.distort.radial_k2 || model.distort.tangential_p1 || model.distort.tangential_p2 || model.distort.radial_k3) + { + intrinsics.coeffs[0] = model.distort.radial_k1; + intrinsics.coeffs[1] = model.distort.radial_k2; + intrinsics.coeffs[2] = model.distort.tangential_p1; + intrinsics.coeffs[3] = model.distort.tangential_p2; + intrinsics.coeffs[4] = model.distort.radial_k3; + + intrinsics.model = RS2_DISTORTION_INVERSE_BROWN_CONRADY; + } + return intrinsics; } } diff --git a/src/l500/l500-depth.h b/src/l500/l500-depth.h index cc34592dd8..a5d58c1e4f 100644 --- a/src/l500/l500-depth.h +++ b/src/l500/l500-depth.h @@ -86,7 +86,7 @@ namespace librealsense explicit l500_depth_sensor(l500_device* owner, std::shared_ptr uvc_device, std::unique_ptr timestamp_reader) : uvc_sensor("L500 Depth Sensor", uvc_device, move(timestamp_reader), owner), _owner(owner), - _depth_invalidation_enabled(true) + _depth_invalidation_enabled(false) { register_option(RS2_OPTION_DEPTH_UNITS, std::make_shared("Number of meters represented by a single depth unit", lazy([&]() { @@ -100,7 +100,7 @@ namespace librealsense 0, 1, 1, - 1, + 0, &_depth_invalidation_enabled, "depth invalidation enabled"); _depth_invalidation_option->on_set([this](float val) diff --git a/src/l500/l500-private.h b/src/l500/l500-private.h index 70b7a533b6..f717494e23 100644 --- a/src/l500/l500-private.h +++ b/src/l500/l500-private.h @@ -108,8 +108,8 @@ namespace librealsense float radial_k1; float radial_k2; float tangential_p1; - float radial_k3; float tangential_p2; + float radial_k3; }; struct pinhole_camera_model diff --git a/src/software-device.cpp b/src/software-device.cpp index d366b4cbda..88a977d075 100644 --- a/src/software-device.cpp +++ b/src/software-device.cpp @@ -21,9 +21,20 @@ namespace librealsense return *sensor; } - void software_device::register_extrinsic(const stream_interface& stream, uint32_t groupd_index) + void software_device::register_extrinsic(const stream_interface& stream) { - register_stream_to_extrinsic_group(stream, groupd_index); + uint32_t max_idx = 0; + std::set bad_groups; + for (auto & pair : _extrinsics) { + if (pair.second.first > max_idx) max_idx = pair.second.first; + if (bad_groups.count(pair.second.first)) continue; // already tried the group + rs2_extrinsics ext; + if (environment::get_instance().get_extrinsics_graph().try_fetch_extrinsics(stream, *pair.second.second, &ext)) { + register_stream_to_extrinsic_group(stream, pair.second.first); + return; + } + } + register_stream_to_extrinsic_group(stream, max_idx+1); } software_sensor& software_device::get_software_sensor(int index) @@ -265,7 +276,7 @@ namespace librealsense }, software_frame.pixels }); auto sd = dynamic_cast(_owner); - sd->register_extrinsic(*vid_profile, _unique_id); + sd->register_extrinsic(*vid_profile); _source.invoke_callback(frame); } diff --git a/src/software-device.h b/src/software-device.h index db95503a2e..a3d6a91ea7 100644 --- a/src/software-device.h +++ b/src/software-device.h @@ -31,7 +31,7 @@ namespace librealsense std::vector markers; return markers; }; - void register_extrinsic(const stream_interface& stream, uint32_t groupd_index); + void register_extrinsic(const stream_interface& stream); private: std::vector> _software_sensors; diff --git a/tools/fw-logger/fw-logs-formating-options.cpp b/tools/fw-logger/fw-logs-formating-options.cpp index b5fb74a000..399e15bbf7 100644 --- a/tools/fw-logger/fw-logs-formating-options.cpp +++ b/tools/fw-logger/fw-logs-formating-options.cpp @@ -79,6 +79,11 @@ namespace fw_logger } } + std::unordered_map> fw_logs_formating_options::get_enums() const + { + return _fw_logs_enum_names_list; + } + bool fw_logs_formating_options::initialize_from_xml() { fw_logs_xml_helper fw_logs_xml(_xml_full_file_path); diff --git a/tools/fw-logger/fw-logs-formating-options.h b/tools/fw-logger/fw-logs-formating-options.h index 3c76f485fb..7dc68e0771 100644 --- a/tools/fw-logger/fw-logs-formating-options.h +++ b/tools/fw-logger/fw-logs-formating-options.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifdef ANDROID #include "../../common/android_helpers.h" @@ -32,6 +33,7 @@ namespace fw_logger bool get_event_data(int id, fw_log_event* log_event_data) const; bool get_file_name(int id, std::string* file_name) const; bool get_thread_name(uint32_t thread_id, std::string* thread_name) const; + std::unordered_map> get_enums() const; bool initialize_from_xml(); private: @@ -39,6 +41,8 @@ namespace fw_logger std::unordered_map _fw_logs_event_list; std::unordered_map _fw_logs_file_names_list; std::unordered_map _fw_logs_thread_names_list; + std::unordered_map> _fw_logs_enum_names_list; + std::string _xml_full_file_path; }; } diff --git a/tools/fw-logger/fw-logs-parser.cpp b/tools/fw-logger/fw-logs-parser.cpp index d6076117bb..59131b6a8c 100644 --- a/tools/fw-logger/fw-logs-parser.cpp +++ b/tools/fw-logger/fw-logs-parser.cpp @@ -50,7 +50,7 @@ namespace fw_logger void fw_logs_parser::fill_log_data(const char* fw_logs, fw_log_data* log_data) { - string_formatter reg_exp; + string_formatter reg_exp(_fw_logs_formating_options.get_enums()); fw_log_event log_event_data; auto* log_binary = reinterpret_cast(fw_logs); diff --git a/tools/fw-logger/fw-logs-xml-helper.cpp b/tools/fw-logger/fw-logs-xml-helper.cpp index 7acb976820..3575da965a 100644 --- a/tools/fw-logger/fw-logs-xml-helper.cpp +++ b/tools/fw-logger/fw-logs-xml-helper.cpp @@ -117,7 +117,36 @@ namespace fw_logger { logs_formating_options->_fw_logs_thread_names_list.insert(pair(id, line)); } - else + else if (res == enums) + { + for (xml_node<>* enum_node = node->first_node(); enum_node; enum_node = enum_node->next_sibling()) + { + for (xml_attribute<>* attribute = enum_node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + string attr(attribute->name(), attribute->name() + attribute->name_size()); + if (attr.compare("Name") == 0) + { + string name_attr_str(attribute->value(), attribute->value() + attribute->value_size()); + vector values; + + for (xml_node<>* enum_value_node = enum_node->first_node(); enum_value_node; enum_value_node = enum_value_node->next_sibling()) + { + for (xml_attribute<>* attribute = enum_value_node->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + string attr(attribute->name(), attribute->name() + attribute->name_size()); + if (attr.compare("Value") == 0) + { + string value_str(attribute->value(), attribute->value() + attribute->value_size()); + values.push_back(value_str); + } + } + } + logs_formating_options->_fw_logs_enum_names_list.insert(pair>(name_attr_str, values)); + } + } + } + } + else return false; } @@ -143,10 +172,50 @@ namespace fw_logger { if (get_thread_node(node, id, line)) return thread; + } + else if (tag.compare("Enums") == 0) + { + return enums; } return none; } + bool fw_logs_xml_helper::get_enum_name_node(xml_node<>* node_file, int* thread_id, string* enum_name) + { + for (xml_attribute<>* attribute = node_file->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + string attr(attribute->name(), attribute->name() + attribute->name_size()); + + if (attr.compare("Name") == 0) + { + string name_attr_str(attribute->value(), attribute->value() + attribute->value_size()); + *enum_name = name_attr_str; + continue; + } + else + return false; + } + + return true; + } + bool fw_logs_xml_helper::get_enum_value_node(xml_node<>* node_file, int* thread_id, string* enum_name) + { + for (xml_attribute<>* attribute = node_file->first_attribute(); attribute; attribute = attribute->next_attribute()) + { + string attr(attribute->name(), attribute->name() + attribute->name_size()); + + if (attr.compare("Value") == 0) + { + string name_attr_str(attribute->value(), attribute->value() + attribute->value_size()); + *enum_name = name_attr_str; + continue; + } + else + return false; + } + + return true; + } bool fw_logs_xml_helper::get_thread_node(xml_node<>* node_file, int* thread_id, string* thread_name) { for (xml_attribute<>* attribute = node_file->first_attribute(); attribute; attribute = attribute->next_attribute()) diff --git a/tools/fw-logger/fw-logs-xml-helper.h b/tools/fw-logger/fw-logs-xml-helper.h index 231004d676..db6a087e2f 100644 --- a/tools/fw-logger/fw-logs-xml-helper.h +++ b/tools/fw-logger/fw-logs-xml-helper.h @@ -16,6 +16,7 @@ namespace fw_logger event, file, thread, + enums, none }; @@ -30,6 +31,8 @@ namespace fw_logger node_type get_next_node(xml_node<>* xml_node_list_of_events, int* id, int* num_of_params, std::string* line); bool get_thread_node(xml_node<>* node_file, int* thread_id, std::string* thread_name); bool get_event_node(xml_node<>* node_event, int* event_id, int* num_of_params, std::string* line); + bool get_enum_name_node(xml_node<>* node_file, int* thread_id, std::string* thread_name); + bool get_enum_value_node(xml_node<>* node_file, int* thread_id, std::string* enum_name); bool get_file_node(xml_node<>* node_file, int* file_id, std::string* file_name); bool get_root_node(xml_node<> **node); bool try_load_external_xml(); diff --git a/tools/fw-logger/string-formatter.cpp b/tools/fw-logger/string-formatter.cpp index 1d7d449f4a..57417902b5 100644 --- a/tools/fw-logger/string-formatter.cpp +++ b/tools/fw-logger/string-formatter.cpp @@ -9,7 +9,8 @@ using namespace std; namespace fw_logger { - string_formatter::string_formatter(void) + string_formatter::string_formatter(std::unordered_map> enums) + :_enums(enums) { } @@ -21,15 +22,16 @@ namespace fw_logger bool string_formatter::generate_message(const string& source, int num_of_params, const uint32_t* params, string* dest) { map exp_replace_map; + map enum_replace_map; if (params == nullptr && num_of_params > 0) return false; for (int i = 0; i < num_of_params; i++) { - string regular_exp[2]; - string replacement[2]; - stringstream st_regular_exp[2]; - stringstream st_replacement[2]; + string regular_exp[3]; + string replacement[3]; + stringstream st_regular_exp[3]; + stringstream st_replacement[3]; st_regular_exp[0] << "\\{\\b(" << i << ")\\}"; regular_exp[0] = st_regular_exp[0].str(); @@ -47,12 +49,17 @@ namespace fw_logger replacement[1] = st_replacement[1].str(); exp_replace_map[regular_exp[1]] = replacement[1]; + + st_regular_exp[2] << "\\{\\b(" << i << "),[a-zA-Z]+\\}"; + regular_exp[2] = st_regular_exp[2].str(); + + enum_replace_map[regular_exp[2]] = params[i]; } - return replace_params(source, exp_replace_map, dest); + return replace_params(source, exp_replace_map, enum_replace_map, dest); } - bool string_formatter::replace_params(const string& source, const map& exp_replace_map, string* dest) const + bool string_formatter::replace_params(const string& source, const map& exp_replace_map, const map& enum_replace_map, string* dest) { string source_temp(source); @@ -60,10 +67,45 @@ namespace fw_logger { string destTemp; regex e(exp_replace_it->first); - regex_replace(back_inserter(destTemp), source_temp.begin(), source_temp.end(), e, exp_replace_it->second); + auto res = regex_replace(back_inserter(destTemp), source_temp.begin(), source_temp.end(), e, exp_replace_it->second); source_temp = destTemp; + } + for (auto exp_replace_it = enum_replace_map.begin(); exp_replace_it != enum_replace_map.end(); exp_replace_it++) + { + string destTemp; + regex e(exp_replace_it->first); + std::smatch m; + std::regex_search(source_temp, m, std::regex(e)); + + string enum_name; + + string st_regular_exp = "[a-zA-Z]+"; + regex e1(st_regular_exp); + + for(auto exp = 0; exp0 && _enums.find(enum_name) != _enums.end()) + { + auto vec = _enums[enum_name]; + regex e3 = e; + auto res1 = regex_replace(back_inserter(destTemp), source_temp.begin(), source_temp.end(), e3, vec[exp_replace_it->second]); + source_temp = destTemp; + } + } + } } + *dest = source_temp; return true; } diff --git a/tools/fw-logger/string-formatter.h b/tools/fw-logger/string-formatter.h index 437ebe1b3f..8b9a5c9cd8 100644 --- a/tools/fw-logger/string-formatter.h +++ b/tools/fw-logger/string-formatter.h @@ -4,18 +4,22 @@ #include #include #include +#include +#include namespace fw_logger { class string_formatter { public: - string_formatter(void); + string_formatter(std::unordered_map> enums); ~string_formatter(void); bool generate_message(const std::string& source, int num_of_params, const uint32_t* params, std::string* dest); private: - bool replace_params(const std::string& source, const std::map& exp_replace_map, std::string* dest) const; + bool replace_params(const std::string& source, const std::map& exp_replace_map, const std::map& enum_replace_map, std::string* dest); + + std::unordered_map> _enums; }; } diff --git a/unit-tests/CMakeLists.txt b/unit-tests/CMakeLists.txt index 4cd5dd95b8..fd8f013007 100644 --- a/unit-tests/CMakeLists.txt +++ b/unit-tests/CMakeLists.txt @@ -51,6 +51,13 @@ add_custom_command(TARGET live-test POST_BUILD ${Deployment_Location} ) +# copy wheel odometry calibration file to build folder +add_custom_command(TARGET live-test POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/resources/calibration_odometry.json + ${CMAKE_CURRENT_BINARY_DIR}/calibration_odometry.json +) + #Post-Processing data set for unit-tests #message(STATUS "Post processing deployment directory=${Deployment_Location}") list(APPEND PP_Tests_List 1551257764229 # D415_DS(2) diff --git a/unit-tests/unit-tests-live.cpp b/unit-tests/unit-tests-live.cpp index b34d26751d..7f653ab1a2 100644 --- a/unit-tests/unit-tests-live.cpp +++ b/unit-tests/unit-tests-live.cpp @@ -5548,7 +5548,6 @@ TEST_CASE("Wheel_Odometry_API", "[live]") REQUIRE(profile); REQUIRE_NOTHROW(dev = profile.get_device()); REQUIRE(dev); - disable_sensitive_options_for(dev); dev_type PID = get_PID(dev); CAPTURE(PID.first); @@ -5570,7 +5569,7 @@ TEST_CASE("Wheel_Odometry_API", "[live]") THEN("Load wheel odometry calibration") { std::ifstream calibrationFile("calibration_odometry.json"); - if (calibrationFile) + REQUIRE(calibrationFile); { const std::string json_str((std::istreambuf_iterator(calibrationFile)), std::istreambuf_iterator()); diff --git a/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RegionOfInterest.java b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RegionOfInterest.java new file mode 100644 index 0000000000..7843eaf182 --- /dev/null +++ b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RegionOfInterest.java @@ -0,0 +1,16 @@ +package com.intel.realsense.librealsense; + +public class RegionOfInterest { + public int minX; + public int minY; + public int maxX; + public int maxY; + + public RegionOfInterest(){} + public RegionOfInterest(int minX,int minY, int maxX, int maxY){ + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } +} diff --git a/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RoiSensor.java b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RoiSensor.java new file mode 100644 index 0000000000..5742485079 --- /dev/null +++ b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/RoiSensor.java @@ -0,0 +1,26 @@ +package com.intel.realsense.librealsense; + +public class RoiSensor extends Sensor { + + RoiSensor(long handle) { + super(handle); + mOwner = false; + } + + public void setRegionOfInterest(RegionOfInterest roi) throws Exception{ + nSetRegionOfInterest(mHandle, roi.minX, roi.minY, roi.maxX, roi.maxY); + } + + public void setRegionOfInterest(int minX, int minY, int maxX, int maxY) throws Exception{ + nSetRegionOfInterest(mHandle, minX, minY, maxX, maxY); + } + + public RegionOfInterest getRegionOfInterest() throws Exception { + RegionOfInterest rv = new RegionOfInterest(); + nGetRegionOfInterest(mHandle, rv); + return rv; + } + + private static native void nSetRegionOfInterest(long handle, int minX, int minY, int maxX, int maxY); + private static native void nGetRegionOfInterest(long handle, RegionOfInterest roi); +} diff --git a/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/Sensor.java b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/Sensor.java index abf1d6310f..c5882866e8 100644 --- a/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/Sensor.java +++ b/wrappers/android/librealsense/src/main/java/com/intel/realsense/librealsense/Sensor.java @@ -18,9 +18,17 @@ public List getStreamProfiles(){ return rv; } + public T as(Extension extension) { + switch (extension){ + case ROI: return (T) new RoiSensor(mHandle); + } + throw new RuntimeException("this sensor is not extendable to " + extension.name()); + } + @Override public void close() { - nRelease(mHandle); + if(mOwner) + nRelease(mHandle); } private static native long[] nGetStreamProfiles(long handle); diff --git a/wrappers/matlab/frame_queue.m b/wrappers/matlab/frame_queue.m index b85dc58813..77a5c02e25 100644 --- a/wrappers/matlab/frame_queue.m +++ b/wrappers/matlab/frame_queue.m @@ -39,5 +39,9 @@ function delete(this) function cap = capacity(this) cap = realsense.librealsense_mex('rs2::frame_queue', 'capacity', this.objectHandle); end + function keep = keep_frames(this) + cap = realsense.librealsense_mex('rs2::frame_queue', 'keep_frames', this.objectHandle); + end + end end -end \ No newline at end of file +end diff --git a/wrappers/matlab/librealsense_mex.cpp b/wrappers/matlab/librealsense_mex.cpp index dbcb56aa79..8d1b3f0f1e 100644 --- a/wrappers/matlab/librealsense_mex.cpp +++ b/wrappers/matlab/librealsense_mex.cpp @@ -917,7 +917,7 @@ void make_factory(){ // rs2::processing_block [?] { ClassFactory frame_queue_factory("rs2::frame_queue"); - frame_queue_factory.record("new", 1, 0, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + frame_queue_factory.record("new", 1, 0, 2, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) { if (inc == 0) { outv[0] = MatlabParamParser::wrap(rs2::frame_queue()); @@ -926,6 +926,11 @@ void make_factory(){ auto capacity = MatlabParamParser::parse(inv[0]); outv[0] = MatlabParamParser::wrap(rs2::frame_queue(capacity)); } + else if (inc == 2) { + auto capacity = MatlabParamParser::parse(inv[0]); + auto keep_frames = MatlabParamParser::parse(inv[1]); + outv[0] = MatlabParamParser::wrap(rs2::frame_queue(capacity, keep_frames)); + } }); // rs2::frame_queue::enqueue(frame) [?] frame_queue_factory.record("wait_for_frame", 1, 1, 2, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) @@ -945,6 +950,11 @@ void make_factory(){ auto thiz = MatlabParamParser::parse(inv[0]); outv[0] = MatlabParamParser::wrap(thiz.capacity()); }); + frame_queue_factory.record("keep_frames", 1, 1, [](int outc, mxArray* outv[], int inc, const mxArray* inv[]) + { + auto thiz = MatlabParamParser::parse(inv[0]); + outv[0] = MatlabParamParser::wrap(thiz.keep_frames()); + }); factory->record(frame_queue_factory); } // TODO: need to understand how to call matlab functions from within C++ before async things can be implemented. diff --git a/wrappers/python/examples/frame_queue_example.py b/wrappers/python/examples/frame_queue_example.py new file mode 100644 index 0000000000..952c339109 --- /dev/null +++ b/wrappers/python/examples/frame_queue_example.py @@ -0,0 +1,86 @@ +## License: Apache 2.0. See LICENSE file in root directory. +## Copyright(c) 2019 Intel Corporation. All Rights Reserved. + +##################################################### +## Frame Queues ## +##################################################### + +# First import the library +import pyrealsense2 as rs +import time + +# Implement two "processing" functions, each of which +# occassionally lags and takes longer to process a frame. +def slow_processing(frame): + n = frame.get_frame_number() + if n % 20 == 0: + time.sleep(1/4) + print(n) + +def slower_processing(frame): + n = frame.get_frame_number() + if n % 20 == 0: + time.sleep(1) + print(n) + +try: + # Create a pipeline + pipeline = rs.pipeline() + + # Create a config and configure the pipeline to stream + # different resolutions of color and depth streams + config = rs.config() + config.enable_stream(rs.stream.depth, 640, 360, rs.format.z16, 30) + + # Start streaming to the slow processing function. + # This stream will lag, causing the occasional frame drop. + print("Slow callback") + pipeline.start(config) + start = time.time() + while time.time() - start < 5: + frames = pipeline.wait_for_frames() + slow_processing(frames) + pipeline.stop() + + # Start streaming to the the slow processing function by way of a frame queue. + # This stream will occasionally hiccup, but the frame_queue will prevent frame loss. + print("Slow callback + queue") + queue = rs.frame_queue(50) + pipeline.start(config, queue) + start = time.time() + while time.time() - start < 5: + frames = queue.wait_for_frame() + slow_processing(frames) + pipeline.stop() + + # Start streaming to the the slower processing function by way of a frame queue. + # This stream will drop frames because the delays are long enough that the backed up + # frames use the entire internal frame pool preventing the SDK from creating more frames. + print("Slower callback + queue") + queue = rs.frame_queue(50) + pipeline.start(config, queue) + start = time.time() + while time.time() - start < 5: + frames = queue.wait_for_frame() + slower_processing(frames) + pipeline.stop() + + # Start streaming to the slower processing function by way of a keeping frame queue. + # This stream will no longer drop frames because the frame queue tells the SDK + # to remove the frames it holds from the internal frame queue, allowing the SDK to + # allocate space for and create more frames . + print("Slower callback + keeping queue") + queue = rs.frame_queue(50, keep_frames=True) + pipeline.start(config, queue) + start = time.time() + while time.time() - start < 5: + frames = queue.wait_for_frame() + slower_processing(frames) + pipeline.stop() + +except Exception as e: + print(e) +except: + print("A different Error") +else: + print("Done") \ No newline at end of file diff --git a/wrappers/python/pyrs_advanced_mode.cpp b/wrappers/python/pyrs_advanced_mode.cpp index 3586d17839..72085a96fb 100644 --- a/wrappers/python/pyrs_advanced_mode.cpp +++ b/wrappers/python/pyrs_advanced_mode.cpp @@ -211,6 +211,15 @@ void init_advanced_mode(py::module &m) { return ss.str(); }); + py::class_ _STAFactor(m, "STAFactor"); + _STAFactor.def(py::init<>()) + .def_readwrite("a_factor", &STAFactor::amplitude) + .def("__repr__", [](const STAFactor &e) { + std::stringstream ss; + ss << "a_factor: " << e.amplitude; + return ss.str(); + }); + py::class_ rs400_advanced_mode(m, "rs400_advanced_mode"); rs400_advanced_mode.def(py::init(), "device"_a) .def("toggle_advanced_mode", &rs400::advanced_mode::toggle_advanced_mode, "enable"_a) diff --git a/wrappers/python/pyrs_context.cpp b/wrappers/python/pyrs_context.cpp index 03d81000c8..5de84cab76 100644 --- a/wrappers/python/pyrs_context.cpp +++ b/wrappers/python/pyrs_context.cpp @@ -31,7 +31,7 @@ void init_context(py::module &m) { self.set_devices_changed_callback(callback); }, "Register devices changed callback.", "callback"_a) .def("load_device", &rs2::context::load_device, "Creates a devices from a RealSense file.\n" - "On successful load, the device will be appended to the context and a devices_changed event triggered." + "On successful load, the device will be appended to the context and a devices_changed event triggered.", "filename"_a) .def("unload_device", &rs2::context::unload_device, "filename"_a) // No docstring in C++ .def("unload_tracking_module", &rs2::context::unload_tracking_module); // No docstring in C++ diff --git a/wrappers/python/pyrs_processing.cpp b/wrappers/python/pyrs_processing.cpp index ab38fe3763..67b50372f9 100644 --- a/wrappers/python/pyrs_processing.cpp +++ b/wrappers/python/pyrs_processing.cpp @@ -9,7 +9,7 @@ void init_processing(py::module &m) { py::class_ frame_source(m, "frame_source", "The source used to generate frames, which is usually done by the low level driver for each sensor. " "frame_source is one of the parameters of processing_block's callback function, which can be used to re-generate the " "frame and via frame_ready invoke another callback function to notify application frame is ready."); - frame_source.def("allocate_video_frame", &rs2::frame_source::allocate_video_frame, "Allocate a new video frame with given params" + frame_source.def("allocate_video_frame", &rs2::frame_source::allocate_video_frame, "Allocate a new video frame with given params", "profile"_a, "original"_a, "new_bpp"_a = 0, "new_width"_a = 0, "new_height"_a = 0, "new_stride"_a = 0, "frame_type"_a = RS2_EXTENSION_VIDEO_FRAME) .def("allocate_points", &rs2::frame_source::allocate_points, "profile"_a, @@ -26,6 +26,7 @@ void init_processing(py::module &m) { "developers who are not using async APIs."); frame_queue.def(py::init()) .def(py::init<>()) + .def(py::init(), "capacity"_a, "keep_frames"_a = false) .def("enqueue", &rs2::frame_queue::enqueue, "Enqueue a new frame into the queue.", "f"_a) .def("wait_for_frame", &rs2::frame_queue::wait_for_frame, "Wait until a new frame " "becomes available in the queue and dequeue it.", "timeout_ms"_a = 5000, py::call_guard()) @@ -39,8 +40,9 @@ void init_processing(py::module &m) { auto success = self.try_wait_for_frame(&frame, timeout_ms); return std::make_tuple(success, frame); }, "timeout_ms"_a = 5000, py::call_guard()) // No docstring in C++ - .def("__call__", &rs2::frame_queue::operator(), "Identical to calling enqueue", "f"_a) - .def("capacity", &rs2::frame_queue::capacity, "Return the capacity of the queue"); + .def("__call__", &rs2::frame_queue::operator(), "Identical to calling enqueue.", "f"_a) + .def("capacity", &rs2::frame_queue::capacity, "Return the capacity of the queue.") + .def("keep_frames", &rs2::frame_queue::keep_frames, "Return whether or not the queue calls keep on enqueued frames."); py::class_ processing_block(m, "processing_block", "Define the processing block workflow, inherit this class to " "generate your own processing_block."); diff --git a/wrappers/python/pyrs_record_playback.cpp b/wrappers/python/pyrs_record_playback.cpp index 8db2e8cde3..f01f732a5f 100644 --- a/wrappers/python/pyrs_record_playback.cpp +++ b/wrappers/python/pyrs_record_playback.cpp @@ -16,12 +16,12 @@ void init_record_playback(py::module &m) { .def("file_name", &rs2::playback::file_name, "The name of the playback file.") .def("get_position", &rs2::playback::get_position, "Retrieves the current position of the playback in the file in terms of time. Units are expressed in nanoseconds.") .def("get_duration", &rs2::playback::get_duration, "Retrieves the total duration of the file.") - .def("seek", &rs2::playback::seek, "Sets the playback to a specified time point of the played data." "time"_a) + .def("seek", &rs2::playback::seek, "Sets the playback to a specified time point of the played data.", "time"_a) .def("is_real_time", &rs2::playback::is_real_time, "Indicates if playback is in real time mode or non real time.") .def("set_real_time", &rs2::playback::set_real_time, "Set the playback to work in real time or non real time. In real time mode, playback will " "play the same way the file was recorded. If the application takes too long to handle the callback, frames may be dropped. In non real time " "mode, playback will wait for each callback to finish handling the data before reading the next frame. In this mode no frames will be dropped, " - "and the application controls the framerate of playback via callback duration." "real_time"_a) + "and the application controls the framerate of playback via callback duration.", "real_time"_a) // set_playback_speed? .def("set_status_changed_callback", [](rs2::playback& self, std::function callback) { self.set_status_changed_callback(callback); diff --git a/wrappers/python/pyrsutil.cpp b/wrappers/python/pyrsutil.cpp index 8f52c40243..6256e7c4ba 100644 --- a/wrappers/python/pyrsutil.cpp +++ b/wrappers/python/pyrsutil.cpp @@ -11,27 +11,30 @@ void init_util(py::module &m) { std::array pixel{}; rs2_project_point_to_pixel(pixel.data(), &intrin, point.data()); return pixel; - }, "Given a point in 3D space, compute the corresponding pixel coordinates in an image with no distortion or forward distortion coefficients produced by the same camera"); + }, "Given a point in 3D space, compute the corresponding pixel coordinates in an image with no distortion or forward distortion coefficients produced by the same camera", + "intrin"_a, "point"_a); m.def("rs2_deproject_pixel_to_point", [](const rs2_intrinsics& intrin, const std::array& pixel, float depth)->std::array { std::array point{}; rs2_deproject_pixel_to_point(point.data(), &intrin, pixel.data(), depth); return point; - }, "Given pixel coordinates and depth in an image with no distortion or inverse distortion coefficients, compute the corresponding point in 3D space relative to the same camera"); + }, "Given pixel coordinates and depth in an image with no distortion or inverse distortion coefficients, compute the corresponding point in 3D space relative to the same camera", + "intrin"_a, "pixel"_a, "depth"_a); m.def("rs2_transform_point_to_point", [](const rs2_extrinsics& extrin, const std::array& from_point)->std::array { std::array to_point{}; rs2_transform_point_to_point(to_point.data(), &extrin, from_point.data()); return to_point; - }, "Transform 3D coordinates relative to one sensor to 3D coordinates relative to another viewpoint"); + }, "Transform 3D coordinates relative to one sensor to 3D coordinates relative to another viewpoint", + "extrin"_a, "from_point"_a); m.def("rs2_fov", [](const rs2_intrinsics& intrin)->std::array { std::array to_fow{}; rs2_fov(&intrin, to_fow.data()); return to_fow; - }, "Calculate horizontal and vertical field of view, based on video intrinsics"); + }, "Calculate horizontal and vertical field of view, based on video intrinsics", "intrin"_a); /** end rsutil.h **/ }