Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PLY options #4906

Closed
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 7 additions & 9 deletions common/model-views.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,16 +289,14 @@ namespace rs2
texture_data[idx], texture_data[idx + 1], texture_data[idx + 2]);
}

void export_to_ply(const std::string& fname, notifications_model& ns, points p, video_frame texture, bool notify)
void export_frame(const std::string& fname, std::unique_ptr<rs2::filter> exporter, notifications_model& ns, frame data, bool notify)
{
std::thread([&ns, p, texture, fname, notify]() mutable {
if (p)
{
p.export_to_ply(fname, texture);
if (notify) ns.add_notification({ to_string() << "Finished saving 3D view " << (texture ? "to " : "without texture to ") << fname,
RS2_LOG_SEVERITY_INFO,
RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
}
std::thread([exporter = std::move(exporter), &ns, data, fname, notify]() mutable {
exporter->process(data);
if (notify) ns.add_notification({ to_string() << "Finished saving 3D view " << (data.is<rs2::points>() ? "without texture to " : "to ") <<
fname,
RS2_LOG_SEVERITY_INFO,
RS2_NOTIFICATION_CATEGORY_UNKNOWN_ERROR });
}).detach();
}

Expand Down
8 changes: 7 additions & 1 deletion common/model-views.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,12 @@ namespace rs2
static const char* vsync { "performance.vsync" };
static const char* font_oversample { "performance.font_oversample.v2" };
}
namespace ply
{
static const char* mesh { "ply.mesh" };
static const char* use_normals { "ply.normals" };
static const char* encoding { "ply.encoding" };
}
}

namespace textual_icons
Expand Down Expand Up @@ -949,7 +955,7 @@ namespace rs2
std::shared_ptr<gl::uploader> uploader; // GL element that helps pre-emptively copy frames to the GPU
};

void export_to_ply(const std::string& file_name, notifications_model& ns, points p, video_frame texture, bool notify = true);
void export_frame(const std::string& fname, std::unique_ptr<rs2::filter> exporter, notifications_model& ns, rs2::frame data, bool notify = true);

// Auxillary function to save stream data in its internal (raw) format
bool save_frame_raw_data(const std::string& filename, rs2::frame frame);
Expand Down
4 changes: 4 additions & 0 deletions common/ux-window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ namespace rs2
config_file::instance().set_default(configurations::performance::show_fps, false);
config_file::instance().set_default(configurations::performance::vsync, true);

config_file::instance().set_default(configurations::ply::mesh, true);
config_file::instance().set_default(configurations::ply::use_normals, false);
config_file::instance().set_default(configurations::ply::encoding, 0);

#ifdef __APPLE__
config_file::instance().set_default(configurations::performance::font_oversample, 8);
config_file::instance().set_default(configurations::performance::enable_msaa, true);
Expand Down
245 changes: 219 additions & 26 deletions common/viewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,23 @@

namespace rs2
{
frameset_allocator::frameset_allocator(viewer_model* viewer) : owner(viewer),
filter([this](frame f, frame_source& s)
{
std::vector<rs2::frame> frame_vec;
auto tex = owner->get_last_texture()->get_last_frame(true);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pls check whether the capture is safe if device is disconnected while processing the export

if (tex)
{
frame_vec.push_back(tex);
frame_vec.push_back(f);
auto frame = s.allocate_composite_frame(frame_vec);
if (frame)
s.frame_ready(std::move(frame));
}
else
s.frame_ready(std::move(f));
}) {}

void viewer_model::render_pose(rs2::rect stream_rect, float buttons_heights)
{
int num_of_pose_buttons = 2; // trajectory, info
Expand Down Expand Up @@ -83,7 +100,7 @@ namespace rs2
//ImGui::End();
}

void viewer_model::show_3dviewer_header(ImFont* font, rs2::rect stream_rect, bool& paused, std::string& error_message)
void viewer_model::show_3dviewer_header(ImFont* large_font, ImFont* font, rs2::rect stream_rect, bool& paused, std::string& error_message)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PLs add a comment what is the 2nd font for

{
int combo_boxes = 0;
const float combo_box_width = 200;
Expand Down Expand Up @@ -264,6 +281,193 @@ namespace rs2
}
}

ImGui::PopStyleColor(3);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is strange that the section starts with pop and not push - seem to indicate and issue elsewhere.

Please encapsulate this fragment into a function call for maintainability.


float w = stream_rect.w * 0.33f;
float h = stream_rect.h * 0.34f;
float x0 = stream_rect.x * 2;
float y0 = stream_rect.y * 6;
ImGui::SetNextWindowPos({ x0, y0 });
ImGui::SetNextWindowSize({ w, h });

auto flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;

ImGui_ScopePushFont(font);
ImGui::PushStyleColor(ImGuiCol_PopupBg, sensor_bg);
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);
ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(15, 15));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 1);

static config_file temp_cfg;
static export_type tab = export_type::ply;
if (ImGui::BeginPopupModal("Export", nullptr, flags))
{
ImGui::SetCursorScreenPos({ (float)(x0), (float)(y0 + 30) });
ImGui::PushStyleColor(ImGuiCol_Button, sensor_bg);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, sensor_bg);
ImGui::PushFont(large_font);
for (auto& exporter : exporters)
{
ImGui::PushStyleColor(ImGuiCol_Text, tab != exporter.first ? light_grey : light_blue);
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != exporter.first ? light_grey : light_blue);
ImGui::SameLine();
if (ImGui::Button(exporter.second.name.c_str(), { w / exporters.size() - 50, 30 }))
{
config_file::instance().set(configurations::viewer::settings_tab, tab);
temp_cfg.set(configurations::viewer::settings_tab, tab);
tab = exporter.first;
}
ImGui::PopStyleColor(2);
}

ImGui::PopFont();
if (tab == export_type::ply)
{
bool mesh = temp_cfg.get(configurations::ply::mesh);
bool use_normals = temp_cfg.get(configurations::ply::use_normals);
if (!mesh) use_normals = false;
int encoding = temp_cfg.get(configurations::ply::encoding);

ImGui::PushStyleColor(ImGuiCol_Text, grey);
ImGui::Text("Polygon File Format defines a flexible systematic scheme for storing 3D data");
ImGui::PopStyleColor();
ImGui::NewLine();
ImGui::SetCursorScreenPos({ (float)(x0 + 15), (float)(y0 + 90) });
ImGui::Separator();
if (ImGui::Checkbox("Meshing", &mesh))
{
temp_cfg.set(configurations::ply::mesh, mesh);
}
ImGui::PushStyleColor(ImGuiCol_Text, grey);
ImGui::Text(" Use faces for meshing by connecting each group of 3 adjacent points");
ImGui::PopStyleColor();
ImGui::Separator();

if (!mesh)
{
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, black);
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, black);
}
if (ImGui::Checkbox("Normals", &use_normals))
{
if (!mesh)
use_normals = false;
else
temp_cfg.set(configurations::ply::use_normals, use_normals);
}
if (!mesh)
{
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Enable meshing to allow vertex normals calculation");
}
ImGui::PopStyleColor(2);
ImGui::PopStyleVar();
}

ImGui::PushStyleColor(ImGuiCol_Text, grey);
ImGui::Text(" Calculate vertex normals and add them to the PLY");
ImGui::PopStyleColor();
ImGui::Separator();

ImGui::Text("Encoding:");
ImGui::PushStyleColor(ImGuiCol_Text, grey);
ImGui::Text("Save PLY as binary, or as a larger textual human-readable file");
ImGui::PopStyleColor();
if (ImGui::RadioButton("Textual", encoding == 0))
{
encoding = 0;
temp_cfg.set(configurations::ply::encoding, encoding);
}
if (ImGui::RadioButton("Binary", encoding == 1))
{
encoding = 1;
temp_cfg.set(configurations::ply::encoding, encoding);
}

auto curr_exporter = exporters.find(tab);
assert(curr_exporter != exporters.end()); // every tab should have a corresponding exporter
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The assert will be discarded in release. A run-time error should probably be generated here

rs2::save_to_ply ply;
curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_MESH] = mesh;
curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_NORMALS] = use_normals;
curr_exporter->second.options[rs2::save_to_ply::OPTION_PLY_BINARY] = encoding;
}

ImGui::PopStyleColor(2); // button color

auto apply = [&]() {
config_file::instance() = temp_cfg;
update_configuration();
};

ImGui::SetCursorScreenPos({ (float)(x0 + w / 2 - 190), (float)(y0 + h - 30) });
if (ImGui::Button("OK", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
apply();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("%s", "Save settings and close");
}
ImGui::SameLine();

if (ImGui::Button("Export", ImVec2(120, 0)))
{
auto curr_exporter = exporters.find(tab);
assert(curr_exporter != exporters.end()); // every tab should have a corresponding exporter
if (auto ret = file_dialog_open(save_file, curr_exporter->second.filters.c_str(), NULL, NULL))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as in line 392

{
auto model = ppf.get_points();
frame tex;
if (selected_tex_source_uid >= 0 && streams.find(selected_tex_source_uid) != streams.end())
{
tex = streams[selected_tex_source_uid].texture->get_last_frame(true);
if (tex) ppf.update_texture(tex);
}

std::string fname(ret);
if (!ends_with(to_lower(fname), curr_exporter->second.extension)) fname += curr_exporter->second.extension;

std::unique_ptr<rs2::filter> exporter;
if (tab == 0)
exporter = std::unique_ptr<rs2::filter>(new rs2::save_to_ply(fname));
auto data = alloc.process(last_points);

for (auto& option : curr_exporter->second.options)
{
exporter->set_option(option.first, option.second);
}

export_frame(fname, std::move(exporter), not_model, data);
exporter.reset();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to reset it explicitly just before scoping out ?

}
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("%s", "Save settings and export file");
}
ImGui::SameLine();
if (ImGui::Button("Cancel", ImVec2(120, 0)))
{
ImGui::CloseCurrentPopup();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("%s", "Close window without saving any changes to the settings");
}

ImGui::EndPopup();
}
ImGui::PopStyleVar(2);

ImGui::PushStyleColor(ImGuiCol_Button, header_window_bg);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, header_window_bg);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, header_window_bg);

ImGui::SetCursorPos({ stream_rect.w - 32 * num_of_buttons - 5, 0 });

if (paused)
Expand Down Expand Up @@ -303,24 +507,10 @@ namespace rs2
}

ImGui::SameLine();

if (ImGui::Button(textual_icons::floppy, { 24, buttons_heights }))
{
if (auto ret = file_dialog_open(save_file, "Polygon File Format (PLY)\0*.ply\0", NULL, NULL))
{
auto model = ppf.get_points();

frame tex;
if (selected_tex_source_uid >= 0 && streams.find(selected_tex_source_uid) != streams.end())
{
tex = streams[selected_tex_source_uid].texture->get_last_frame(true);
if (tex) ppf.update_texture(tex);
}

std::string fname(ret);
if (!ends_with(to_lower(fname), ".ply")) fname += ".ply";
export_to_ply(fname.c_str(), not_model, last_points, last_texture->get_last_frame());
}
temp_cfg = config_file::instance();
ImGui::OpenPopup("Export");
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Export 3D model to PLY format");
Expand Down Expand Up @@ -399,16 +589,11 @@ namespace rs2
}

auto total_top_bar_height = top_bar_height * (1 + pose_render); // may include single bar or additional bar for pose

ImGui::PopStyleColor(5);

ImGui::PushStyleColor(ImGuiCol_Text, light_grey);
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, white);

ImGui::PushStyleColor(ImGuiCol_Button, header_window_bg);
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, header_window_bg);
ImGui::PushStyleColor(ImGuiCol_ButtonActive, header_window_bg);

auto old_pos = ImGui::GetCursorScreenPos();
ImVec2 pos { stream_rect.x + stream_rect.w - 215, stream_rect.y + total_top_bar_height + 5 };
ImGui::SetCursorScreenPos(pos);
Expand Down Expand Up @@ -567,16 +752,19 @@ namespace rs2
viewer_model::viewer_model()
: ppf(*this),
synchronization_enable(true),
zo_sensors(0)
zo_sensors(0),
alloc(this)
{
syncer = std::make_shared<syncer_model>();
reset_camera();
rs2_error* e = nullptr;
not_model.add_log(to_string() << "librealsense version: " << api_version_to_string(rs2_get_api_version(&e)) << "\n");

update_configuration();

check_permissions();
export_model exp_model("PLY", ".ply", "Polygon File Format(PLY)\0 * .ply");
exporters.insert(std::pair<export_type, export_model>(export_type::ply, exp_model));
}

void viewer_model::gc_streams()
Expand Down Expand Up @@ -1871,8 +2059,8 @@ namespace rs2
temp_cfg.set(configurations::viewer::settings_tab, tab);
}
ImGui::PopStyleColor(2);

ImGui::SameLine();

ImGui::PushStyleColor(ImGuiCol_Text, tab != 3 ? light_grey : light_blue);
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, tab != 3 ? light_grey : light_blue);
if (ImGui::Button("Updates", { 120, 30 }))
Expand Down Expand Up @@ -2493,6 +2681,11 @@ namespace rs2
return false;
}

std::shared_ptr<texture_buffer> viewer_model::get_last_texture()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seem to be a public member - what is the getter for ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

last_texture is private

{
return last_texture;
}

std::vector<frame> rs2::viewer_model::get_frames(frame frame)
{
std::vector<rs2::frame> res;
Expand Down Expand Up @@ -2578,7 +2771,7 @@ namespace rs2
if (paused)
show_paused_icon(window.get_large_font(), static_cast<int>(panel_width + 15), static_cast<int>(panel_y + 15 + 32), 0);

show_3dviewer_header(window.get_font(), viewer_rect, paused, error_message);
show_3dviewer_header(window.get_large_font(), window.get_font(), viewer_rect, paused, error_message);

update_3d_camera(window, viewer_rect);

Expand Down
Loading