-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Fixing Depth Alignment in Align-GL processing block #12556
Merged
Nir-Az
merged 3 commits into
IntelRealSense:development
from
Arun-Prasad-V:align-gl-example
Jan 18, 2024
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# License: Apache 2.0. See LICENSE file in root directory. | ||
# Copyright(c) 2024 Intel Corporation. All Rights Reserved. | ||
# minimum required cmake version: 3.1.0 | ||
cmake_minimum_required(VERSION 3.1.0) | ||
|
||
project(RealsenseExamplesAlignGl ) | ||
|
||
# Save the command line compile commands in the build output | ||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1) | ||
|
||
if(BUILD_GRAPHICAL_EXAMPLES AND NOT APPLE) | ||
add_executable(rs-align-gl rs-align-gl.cpp ../../third-party/imgui/imgui.cpp ../../third-party/imgui/imgui_draw.cpp ../../third-party/imgui/imgui_impl_glfw.cpp) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Have you tried to use example-imgui.hpp |
||
set_property(TARGET rs-align-gl PROPERTY CXX_STANDARD 11) | ||
target_link_libraries(rs-align-gl ${DEPENDENCIES} realsense2-gl) | ||
include_directories(../../common ../../third-party/imgui ../../examples) | ||
set_target_properties (rs-align-gl PROPERTIES FOLDER Examples) | ||
install(TARGETS rs-align-gl RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) | ||
endif() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
# rs-align-gl Sample | ||
|
||
## Overview | ||
|
||
> Due to driver limitations built-in GPU capabilities are not available at the moment on Mac-OS | ||
|
||
This example demonstrates the concept of spatial stream alignment **accelerated with GPU**. | ||
For example usecase of alignment, please check out align-advanced and measure demos. | ||
The need for spatial alignment (from here "align") arises from the fact | ||
that not all camera streams are captured from a single viewport. | ||
|
||
|
||
Align process lets the user translate images from one viewport to another. | ||
That said, results of align are synthetic streams, and suffer from several artifacts: | ||
1. **Sampling** - mapping stream to a different viewport will modify the resolution of the frame | ||
to match the resolution of target viewport. This will either cause downsampling or | ||
upsampling via interpolation. The interpolation used needs to be of type | ||
Nearest Neighbor to avoid introducing non-existing values. | ||
2. **Occlussion** - Some pixels in the resulting image correspond to 3D coordinates that the original | ||
sensor did not see, because these 3D points were occluded in the original viewport. | ||
Such pixels may hold invalid texture values. | ||
|
||
## Expected Output | ||
|
||
The application should open a window and display video stream from the color camera overlayed on top of depth stream data. | ||
The slider in bottom of the window control the transparancy of the overlayed stream. | ||
Checkboxes below allow toggling between depth to color vs color to depth alignment. | ||
|
||
<p align="center"><img src="https://raw.githubusercontent.com/wiki/dorodnic/librealsense/align-expected.gif" alt="screenshot gif"/></p> | ||
|
||
## Code Overview | ||
|
||
In addition to core `realsense2` this example also depends on an auxiliary `realsense2-gl` library. | ||
This is not strictly part of core RealSense functionality, but rather a useful extension. | ||
|
||
So, in addition to standard `#include <librealsense2/rs.hpp>` you need to include: | ||
```cpp | ||
#include <librealsense2-gl/rs_processing_gl.hpp> // Include GPU-Processing API | ||
``` | ||
|
||
This example also uses `IMGUI` library for simple UI rendering: | ||
|
||
> In order to allow texture sharing between processing and rendering application, `rs_processing_gl.hpp` needs to be included **after** including `GLFW`. | ||
|
||
After defining some helper functions and `window` object, we need to initialize GL processing and rendering subsystems: | ||
```cpp | ||
// Once we have a window, initialize GL module | ||
// Pass our window to enable sharing of textures between processed frames and the window | ||
rs2::gl::init_processing(app, use_gpu_processing); | ||
// Initialize rendering module: | ||
rs2::gl::init_rendering(); | ||
``` | ||
|
||
In this example we are interested in `RS2_STREAM_DEPTH` and `RS2_STREAM_COLOR` streams: | ||
```cpp | ||
// Create a pipeline to easily configure and start the camera | ||
rs2::pipeline pipe; | ||
rs2::config cfg; | ||
cfg.enable_stream(RS2_STREAM_DEPTH); | ||
cfg.enable_stream(RS2_STREAM_COLOR); | ||
pipe.start(cfg); | ||
|
||
``` | ||
|
||
SDK class responsible for GL stream alignment is called `rs2::gl::align`. The user should initialize it with desired target stream and applies it to framesets via `process` method. | ||
```cpp | ||
// Define two align objects. One will be used to align | ||
// to depth viewport and the other to color. | ||
// Creating align object is an expensive operation | ||
// that should not be performed in the main loop | ||
rs2::gl::align align_to_depth(RS2_STREAM_DEPTH); | ||
rs2::gl::align align_to_color(RS2_STREAM_COLOR); | ||
// ... | ||
frameset = align_to_depth.process(frameset); | ||
``` | ||
|
||
This example also uses GL colorizer `rs2::gl::colorizer` to colorize the depth image. | ||
```cpp | ||
rs2::gl::colorizer c; | ||
``` | ||
|
||
Next, we render the two stream overlayed on top of each other using OpenGL blending feature: | ||
|
||
```cpp | ||
glEnable(GL_BLEND); | ||
// Use the Alpha channel for blending | ||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
|
||
if (dir == direction::to_depth) | ||
{ | ||
// When aligning to depth, first render depth image | ||
// and then overlay color on top with transparancy | ||
depth_image.render(colorized_depth, { 0, 0, app.width(), app.height() }); | ||
color_image.render(color, { 0, 0, app.width(), app.height() }, alpha); | ||
} | ||
else | ||
{ | ||
// When aligning to color, first render color image | ||
// and then overlay depth image on top | ||
color_image.render(color, { 0, 0, app.width(), app.height() }); | ||
depth_image.render(colorized_depth, { 0, 0, app.width(), app.height() }, 1 - alpha); | ||
} | ||
|
||
glColor4f(1.f, 1.f, 1.f, 1.f); | ||
glDisable(GL_BLEND); | ||
``` | ||
|
||
IMGUI is used to render the slider and two checkboxes: | ||
```cpp | ||
// Render the UI: | ||
ImGui_ImplGlfw_NewFrame(1); | ||
render_slider({ 15.f, app.height() - 60, app.width() - 30, app.height() }, &alpha, &dir); | ||
ImGui::Render(); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,176 @@ | ||
// License: Apache 2.0. See LICENSE file in root directory. | ||
// Copyright(c) 2024 Intel Corporation. All Rights Reserved. | ||
|
||
#include <librealsense2/rs.hpp> | ||
#include "example-imgui.hpp" | ||
#include <librealsense2-gl/rs_processing_gl.hpp> // Include GPU-Processing API | ||
|
||
|
||
/* | ||
This example introduces the concept of spatial stream alignment. | ||
For example usecase of alignment, please check out align-advanced and measure demos. | ||
The need for spatial alignment (from here "align") arises from the fact | ||
that not all camera streams are captured from a single viewport. | ||
Align process lets the user translate images from one viewport to another. | ||
That said, results of align are synthetic streams, and suffer from several artifacts: | ||
1. Sampling - mapping stream to a different viewport will modify the resolution of the frame | ||
to match the resolution of target viewport. This will either cause downsampling or | ||
upsampling via interpolation. The interpolation used needs to be of type | ||
Nearest Neighbor to avoid introducing non-existing values. | ||
2. Occlussion - Some pixels in the resulting image correspond to 3D coordinates that the original | ||
sensor did not see, because these 3D points were occluded in the original viewport. | ||
Such pixels may hold invalid texture values. | ||
*/ | ||
|
||
// This example assumes camera with depth and color | ||
// streams, and direction lets you define the target stream | ||
enum class direction | ||
{ | ||
to_depth, | ||
to_color | ||
}; | ||
|
||
// Forward definition of UI rendering, implemented below | ||
void render_slider(rect location, float* alpha, direction* dir); | ||
|
||
int main(int argc, char * argv[]) try | ||
{ | ||
std::string serial; | ||
if (!device_with_streams({ RS2_STREAM_COLOR,RS2_STREAM_DEPTH }, serial)) | ||
return EXIT_SUCCESS; | ||
|
||
// The following toggle is going to control | ||
// if we will use CPU or GPU for depth data processing | ||
bool use_gpu_processing = true; | ||
|
||
// Create and initialize GUI related objects | ||
window app(1280, 720, "RealSense Align Example"); // Simple window handling | ||
ImGui_ImplGlfw_Init(app, false); // ImGui library intializition | ||
|
||
// Once we have a window, initialize GL module | ||
// Pass our window to enable sharing of textures between processed frames and the window | ||
rs2::gl::init_processing(app, use_gpu_processing); | ||
// Initialize rendering module: | ||
rs2::gl::init_rendering(); | ||
|
||
rs2::gl::colorizer c; // Helper to colorize depth images | ||
texture depth_image, color_image; // Helpers for renderig images | ||
|
||
// Create a pipeline to easily configure and start the camera | ||
rs2::pipeline pipe; | ||
rs2::config cfg; | ||
if (!serial.empty()) | ||
cfg.enable_device(serial); | ||
cfg.enable_stream(RS2_STREAM_DEPTH); | ||
cfg.enable_stream(RS2_STREAM_COLOR); | ||
pipe.start(cfg); | ||
|
||
// Define two align objects. One will be used to align | ||
// to depth viewport and the other to color. | ||
// Creating align object is an expensive operation | ||
// that should not be performed in the main loop | ||
rs2::gl::align align_to_depth(RS2_STREAM_DEPTH); | ||
rs2::gl::align align_to_color(RS2_STREAM_COLOR); | ||
|
||
float alpha = 0.5f; // Transparancy coefficient | ||
direction dir = direction::to_depth; // Alignment direction | ||
|
||
while (app) // Application still alive? | ||
{ | ||
// Using the align object, we block the application until a frameset is available | ||
rs2::frameset frameset = pipe.wait_for_frames(); | ||
|
||
if (dir == direction::to_depth) | ||
{ | ||
// Align all frames to depth viewport | ||
frameset = align_to_depth.process(frameset); | ||
} | ||
else | ||
{ | ||
// Align all frames to color viewport | ||
frameset = align_to_color.process(frameset); | ||
} | ||
// With the aligned frameset we proceed as usual | ||
auto depth = frameset.get_depth_frame(); | ||
auto color = frameset.get_color_frame(); | ||
|
||
auto colorized_depth = c.colorize(depth); | ||
|
||
glEnable(GL_BLEND); | ||
// Use the Alpha channel for blending | ||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||
|
||
if (dir == direction::to_depth) | ||
{ | ||
// When aligning to depth, first render depth image | ||
// and then overlay color on top with transparancy | ||
depth_image.render(colorized_depth, { 0, 0, app.width(), app.height() }); | ||
color_image.render(color, { 0, 0, app.width(), app.height() }, alpha); | ||
} | ||
else | ||
{ | ||
// When aligning to color, first render color image | ||
// and then overlay depth image on top | ||
color_image.render(color, { 0, 0, app.width(), app.height() }); | ||
depth_image.render(colorized_depth, { 0, 0, app.width(), app.height() }, 1 - alpha); | ||
} | ||
|
||
glColor4f(1.f, 1.f, 1.f, 1.f); | ||
glDisable(GL_BLEND); | ||
|
||
// Render the UI: | ||
ImGui_ImplGlfw_NewFrame(1); | ||
render_slider({ 15.f, app.height() - 60, app.width() - 30, app.height() }, &alpha, &dir); | ||
ImGui::Render(); | ||
} | ||
|
||
return EXIT_SUCCESS; | ||
} | ||
catch (const rs2::error & e) | ||
{ | ||
std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl; | ||
return EXIT_FAILURE; | ||
} | ||
catch (const std::exception & e) | ||
{ | ||
std::cerr << e.what() << std::endl; | ||
return EXIT_FAILURE; | ||
} | ||
|
||
void render_slider(rect location, float* alpha, direction* dir) | ||
{ | ||
static const int flags = ImGuiWindowFlags_NoCollapse | ||
| ImGuiWindowFlags_NoScrollbar | ||
| ImGuiWindowFlags_NoSavedSettings | ||
| ImGuiWindowFlags_NoTitleBar | ||
| ImGuiWindowFlags_NoResize | ||
| ImGuiWindowFlags_NoMove; | ||
|
||
ImGui::SetNextWindowPos({ location.x, location.y }); | ||
ImGui::SetNextWindowSize({ location.w, location.h }); | ||
|
||
// Render transparency slider: | ||
ImGui::Begin("slider", nullptr, flags); | ||
ImGui::PushItemWidth(-1); | ||
ImGui::SliderFloat("##Slider", alpha, 0.f, 1.f); | ||
ImGui::PopItemWidth(); | ||
if (ImGui::IsItemHovered()) | ||
ImGui::SetTooltip("Texture Transparancy: %.3f", *alpha); | ||
|
||
// Render direction checkboxes: | ||
bool to_depth = (*dir == direction::to_depth); | ||
bool to_color = (*dir == direction::to_color); | ||
|
||
if (ImGui::Checkbox("Align To Depth", &to_depth)) | ||
{ | ||
*dir = to_depth ? direction::to_depth : direction::to_color; | ||
} | ||
ImGui::SameLine(); | ||
ImGui::SetCursorPosX(location.w - 140); | ||
if (ImGui::Checkbox("Align To Color", &to_color)) | ||
{ | ||
*dir = to_color ? direction::to_color : direction::to_depth; | ||
} | ||
|
||
ImGui::End(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by
save
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember we use this line in other examples
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't realize this. It got included when I took reference
CMakelists.txt
from rs-gl exampleThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, not a big deal but looks redundent
If enabled, generates a compile_commands.json file...