IntelRealSense / librealsense

Intel® RealSense™ SDK
https://www.intelrealsense.com/
Apache License 2.0
7.53k stars 4.81k forks source link

How can we simply rotate 90° a color frame ? #4395

Closed jan-robot closed 5 years ago

jan-robot commented 5 years ago

Hi,

I use a realsense D415 camera vertically. I checked the examples provided, and I would like to do the same thing as "capture" but with a 90 ° rotation in the rendering. Is there a simple way to do that? I'm trying to find more information on the internet but the only similar thing I found was: https://github.com/IntelRealSense/librealsense/issues/3249

But it was only for the depth and I did not find it very useful ...

Thank you in advance.

Code used

`// License: Apache 2.0. See LICENSE file in root directory. // Copyright(c) 2017 Intel Corporation. All Rights Reserved.

include <librealsense2/rs.hpp> // Include RealSense Cross Platform API

include "example.hpp" // Include short list of convenience functions for rendering

// Capture Example demonstrates how to // capture depth and color video streams and render them to the screen

int main(int argc, char * argv[]) try {

rs2::log_to_console(RS2_LOG_SEVERITY_ERROR); // Create a simple OpenGL window for rendering: window app(1280, 720, "RealSense Capture Example"); // Declare two textures on the GPU, one for color and one for depth texture depth_image, color_image;

// Declare depth colorizer for pretty visualization of depth data rs2::colorizer color_map;

rs2::hole_filling_filter hole_filling;

// Declare RealSense pipeline, encapsulating the actual device and sensors rs2::pipeline pipe; // Start streaming with default recommended configuration pipe.start();

while(app) // Application still alive? { rs2::frameset data = pipe.wait_for_frames(); // Wait for next set of frames from the camera

rs2::frame depth = color_map.process(data.get_depth_frame()); // Find and colorize the depth data

rs2::frame color = data.get_color_frame();            // Find the color data

// For cameras that don't have RGB sensor, we'll render infrared frames instead of color if (!color) color = data.get_infrared_frame();

// Render depth on to the first half of the screen and color on to the second depth_image.render(depth, { 0, 0, app.width() / 2, app.height() }); // I want this display rotated with 90 ° angle color_image.render(color, { app.width() / 2, 0, app.width() / 2, app.height() }); // I want this display rotated with 90 ° angle }

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; }

`

ev-mp commented 5 years ago

@jan-robot , the SDK does not provide such functionality, but this is easily achievable with cv::transpose. Note, however, that in case you are planning to use the rotated image in image alignment/point cloud generation, then the camera matrix (intrinsic/extrinsic) should be adjusted accordingly

Mike118 commented 5 years ago

You can add this class in your code

class textureRotate90
{
public:
void render(const rs2::video_frame& frame, const rect& r)
{
upload(frame);
show(r.adjust_ratio({float(height),float(width) }));
}

void upload(const rs2::video_frame& frame)
{
    if (!frame) return;

    if (!gl_handle)
        glGenTextures(1, &gl_handle);
    GLenum err = glGetError();

    auto format = frame.get_profile().format();
    width = frame.get_width();
    height = frame.get_height();
    stream = frame.get_profile().stream_type();

    glBindTexture(GL_TEXTURE_2D, gl_handle);

    switch (format)
    {
    case RS2_FORMAT_RGB8:
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame.get_data());
        break;
    case RS2_FORMAT_RGBA8:
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, frame.get_data());
        break;
    default:
        throw std::runtime_error("The requested format is not suported by this demo!");
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glBindTexture(GL_TEXTURE_2D, 0);
}

GLuint get_gl_handle() { return gl_handle; }

void show(const rect& r) const
{
    if (!gl_handle) return;

    glBindTexture(GL_TEXTURE_2D, gl_handle);
    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUAD_STRIP);
    glTexCoord2f(1.f, 1.f); glVertex2f(r.x , r.y +r.h);
    glTexCoord2f(0.f, 1.f); glVertex2f(r.x, r.y);
    glTexCoord2f(1.f, 0.f); glVertex2f(r.x + r.w, r.y + r.h);
    glTexCoord2f(0.f, 0.f); glVertex2f(r.x + r.w, r.y);
    glEnd();
    glDisable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, 0);

    //draw_text(r.x + 15, r.y + 20, rs2_stream_to_string(stream));
}
private:
GLuint gl_handle = 0;
int width = 0;
int height = 0;
rs2_stream stream = RS2_STREAM_ANY;
};
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
switch (message)
{
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
break;
}

return DefWindowProc(hwnd, message, wparam, lparam);
}

and just replace this line : texture depth_image, color_image; by : textureRotate90 depth_image, color_image;

Of course this is just a "visual trick"

Maybe a more advanced texture class can be directly added in the standard "example.hpp" including some rotation parameter... This may be helpfull ...