[pangolin] [pangolin practice] [pangolin learning and use records]

0 Preface

(1) operation instructions of pangolin

1.1 instructions for cmakelists.txt

find_package(Pangolin REQUIRED)
include_directories(${Pangolin_INCLUDE_DIRS})

add_executable(xxx src/xxx.cpp)
target_link_libraries(xxx ${Pangolin_LIBRARIES})

1.2 use of header files

#include <pangolin/pangolin.h>

1.3 use of code

1.3.1 simple example

  1. Function declaration
void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>>);
  • Input parameter vector < isometriy3d, eigen:: aligned_ Allocator < isometriy3d > >: it is a pose collection of many points
  1. Function implementation
/*******************************************************************************************/
void DrawTrajectory(vector<Isometry3d, Eigen::aligned_allocator<Isometry3d>> poses) {
    // create pangolin window and plot the trajectory
    /*
     * Next, we use the CreateWindowAndBind command to create a window object,
     * The parameters of the entry of the function are the name, width and height of the window,
     * This command is similar to the namedWindow in OpenCV, that is, to create a form for display.
     */
    // Create a GUI window named "Trajectory Viewer" with a size of 640 × six hundred and forty
    pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
    //Start the depth test. At the same time, we launched the deep test function,
    // This function will make pangolin only draw the pixel points on the side facing the lens to avoid confusing perspective relations. Therefore, this function should be enabled in any 3D visualization.
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Create an observation camera view
    pangolin::OpenGlRenderState s_cam(
            pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
            pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
    );
    // Create an observation camera view
    // ProjectMatrix(int w, int h, int fu, int fv, int cu, int cv, int znear, int zfar)
    //      The parameters are the image width and height of the observation camera, the four internal parameters, and the nearest and farthest viewing distance
    // ModelViewLookAt(double x, double y, double z,double lx, double ly, double lz, AxisDirection Up)
    //      The parameters are the position of the camera and the viewpoint position seen by the camera (usually set at the origin)

    //After creating the window, we need to "place" a camera in the window (note that the camera here is a camera for observation, not a camera in SLAM),
    // We need to give the ProjectionMatrix of the camera so that when we interact with the camera,
    // Pangolin will automatically complete the corresponding perspective transformation according to the internal parameter matrix.
    // In addition, we also need to give the position of the camera at the initial time, the viewpoint position of the camera (i.e., which point the optical axis of the camera faces) and which axis of the camera itself faces upward.

    // Create interactive view
    //pangolin::Handler3D handler(s_cam); // Interactive camera view handle
    pangolin::View &d_cam = pangolin::CreateDisplay()
            .SetBounds(0.0, 1.0, 0.0, 1.0, -1024.0f / 768.0f)
            .SetHandler(new pangolin::Handler3D(s_cam));//.SetHandler(&handler);
    //Next, we need to create an interactive view to display the content "captured" by the camera in the previous step. This step is similar to the viewport processing in OpenGL.
    // The first four parameters of the setboundaries() function represent the range (bottom, top, left and right) of the view in the window in turn. You can use relative coordinates (0 ~ 1) and absolute coordinates (use the Attach object).


    while (pangolin::ShouldQuit() == false) {
        // Empty color and depth cache
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);//activation
        //After completing all the above preparations, we can start drawing the graphics we need,
        // First, we use the glclear command to clear the color cache and the depth cache respectively
        // And activate the previously set window object (otherwise, the graphics of the previous frame will be retained in the window, and this "multiple exposure" effect is usually not what we need)


        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

        glLineWidth(2);//Defines the width of the line

        for (size_t i = 0; i < poses.size(); i++) {
            // Draw three coordinate axes of each pose
            Vector3d Ow = poses[i].translation();
            Vector3d Xw = poses[i] * (0.1 * Vector3d(1, 0, 0));
            Vector3d Yw = poses[i] * (0.1 * Vector3d(0, 1, 0));
            Vector3d Zw = poses[i] * (0.1 * Vector3d(0, 0, 1));
            glBegin(GL_LINES);
            glColor3f(1.0, 0.0, 0.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Xw[0], Xw[1], Xw[2]);
            glColor3f(0.0, 1.0, 0.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Yw[0], Yw[1], Yw[2]);
            glColor3f(0.0, 0.0, 1.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Zw[0], Zw[1], Zw[2]);
            glEnd();
        }
        // Draw a line
        for (size_t i = 0; i < poses.size(); i++) {
            glColor3f(0.0, 0.0, 0.0);
            glBegin(GL_LINES);
            auto p1 = poses[i], p2 = poses[i + 1];
            glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
            glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
            glEnd();
        }
        //After painting, you need to refresh the window with the FinishFrame command.
        pangolin::FinishFrame();
        usleep(5000);   // sleep 5 ms
    }
}

1.3.1.1 code analysis

1.3.1.1.1 initialize pangolin
    /*
     * Next, we use the CreateWindowAndBind command to create a window object,
     * The parameters of the entry of the function are the name, width and height of the window,
     * This command is similar to the namedWindow in OpenCV, that is, to create a form for display.
     */
    // Create a GUI window named "Trajectory Viewer" with a size of 640 × six hundred and forty
    pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
    //Start the depth test. At the same time, we launched the deep test function,
    // This function will make pangolin only draw the pixel points on the side facing the lens to avoid confusing perspective relations. Therefore, this function should be enabled in any 3D visualization.
    glEnable(GL_DEPTH_TEST);

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  1. pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);: Create a GUI window named "trajectory viewer" with a size of 640 × 640; The parameters of the function entry are the name, width and height of the window in turn. This command is similar to namedWindow in OpenCV, that is, to create a window for display.
  2. glEnable(GL_DEPTH_TEST);: The depth test function is enabled. This function will make pangolin only draw the pixel points on the side facing the lens to avoid confusing perspective relations. Therefore, this function should be enabled in any 3D visualization.
1.3.1.1.2 create an observation camera view
    // Create an observation camera view
    pangolin::OpenGlRenderState s_cam(
            pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000),
            pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
    );
    // Create an observation camera view
    // ProjectMatrix(int w, int h, int fu, int fv, int cu, int cv, int znear, int zfar)
    //      The parameters are the image width and height of the observation camera, the four internal parameters, and the nearest and farthest viewing distance
    // ModelViewLookAt(double x, double y, double z,double lx, double ly, double lz, AxisDirection Up)
    //      The parameters are the position of the camera and the viewpoint position seen by the camera (usually set at the origin)

    //After creating the window, we need to "place" a camera in the window (note that the camera here is a camera for observation, not a camera in SLAM),
    // We need to give the ProjectionMatrix of the camera so that when we interact with the camera,
    // Pangolin will automatically complete the corresponding perspective transformation according to the internal parameter matrix.
    // In addition, we also need to give the position of the camera at the initial time, the viewpoint position of the camera (i.e., which point the optical axis of the camera faces) and which axis of the camera itself faces upward.
  1. ProjectMatrix(int w, int h, int fu, int fv, int cu, int cv, int znear, int zfar): the parameters are the image width, height, 4 internal parameters and the closest and farthest viewing distance of the observation camera in turn
  2. ModelViewLookAt(double x, double y, double z,double lx, double ly, double lz, AxisDirection Up): the parameters are the position of the camera and the viewpoint position seen by the camera in turn (usually set at the origin)
  3. A camera needs to be "placed" in the window (note that the camera here is a camera for observation rather than a camera in SLAM), and the camera's internal parameter matrix ProjectionMatrix is given so that when we interact with the camera, Pangolin will automatically complete the corresponding perspective transformation according to the internal parameter matrix.
  4. We also need to give the position of the camera at the initial time, the viewpoint position of the camera (i.e., which point the optical axis of the camera faces) and which axis of the camera itself faces upward.
1.3.1.1.3 create interactive views
    // Create interactive view
    //pangolin::Handler3D handler(s_cam); // Interactive camera view handle
    pangolin::View &d_cam = pangolin::CreateDisplay()
            .SetBounds(0.0, 1.0, 0.0, 1.0, -1024.0f / 768.0f)
            .SetHandler(new pangolin::Handler3D(s_cam));//.SetHandler(&handler);
    //Next, we need to create an interactive view to display the content "captured" by the camera in the previous step. This step is similar to the viewport processing in OpenGL.
    // The first four parameters of the setboundaries() function represent the range (bottom, top, left and right) of the view in the window in turn. You can use relative coordinates (0 ~ 1) and absolute coordinates (use the Attach object).
  1. Create an interactive view to display the content "captured" by the camera in the previous step
  2. Setboundaries(): the first four parameters represent the range (bottom, top, left and right) of the view in the window in turn. Relative coordinates (0 ~ 1) and absolute coordinates (use Attach object) can be used
1.3.1.1.4 drawing cycle

The drawing operation is completed in the while() loop

    while (pangolin::ShouldQuit() == false) {
        // Empty color and depth cache
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        d_cam.Activate(s_cam);//activation
        //After completing all the above preparations, we can start drawing the graphics we need,
        // First, we use the glclear command to clear the color cache and the depth cache respectively
        // And activate the previously set window object (otherwise, the graphics of the previous frame will be retained in the window, and this "multiple exposure" effect is usually not what we need)

        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);//Set the color of the background, white here

        //glLineWidth(2);// Defines the width of the line

		//The code for drawing is omitted here and will be shown below

        //After painting, you need to refresh the window with the FinishFrame command.
        pangolin::FinishFrame();
        usleep(5000);   // sleep 5 ms
    }
  1. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); It is to clear the color and depth cache, otherwise the graphics of the previous frame will be retained in the window. This "multiple exposure" effect is usually not what we need
  2. d_cam.Activate(s_cam); Is the window object set before activation
  3. glClearColor(1.0f, 1.0f, 1.0f, 1.0f);: Set the color of the background, white here
  4. pangolin::FinishFrame();: After painting, you need to refresh the window with the finishframe command.
1.3.1.1.5 drawing operation
1.3.1.1.5.1 the coordinate axis of the plotter according to the position and posture of the point
        glLineWidth(2);//Defines the width of the line

        for (size_t i = 0; i < poses.size(); i++) {
            // Draw three coordinate axes of each pose
            Vector3d Ow = poses[i].translation();
            Vector3d Xw = poses[i] * (0.1 * Vector3d(1, 0, 0));
            Vector3d Yw = poses[i] * (0.1 * Vector3d(0, 1, 0));
            Vector3d Zw = poses[i] * (0.1 * Vector3d(0, 0, 1));
            
            glBegin(GL_LINES);
            
            glColor3f(1.0, 0.0, 0.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Xw[0], Xw[1], Xw[2]);
            
            glColor3f(0.0, 1.0, 0.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Yw[0], Yw[1], Yw[2]);
            
            glColor3f(0.0, 0.0, 1.0);
            glVertex3d(Ow[0], Ow[1], Ow[2]);
            glVertex3d(Zw[0], Zw[1], Zw[2]);
            
            glEnd();
        }
1.3.1.1.5.2 draw the line between two postures (postures)
        // Draw a line
        for (size_t i = 0; i < poses.size(); i++) {
        
            glColor3f(0.0, 0.0, 0.0);
            
            glBegin(GL_LINES);
            
            auto p1 = poses[i], p2 = poses[i + 1];
            glVertex3d(p1.translation()[0], p1.translation()[1], p1.translation()[2]);
            glVertex3d(p2.translation()[0], p2.translation()[1], p2.translation()[2]);
            
            glEnd();
        }
1.3.1.1.5.3 dot drawing
    glPointSize(2);//Size of set point
    glBegin(GL_POINTS);//Paint set to point
    for (auto& landmark : active_landmarks_) {//Obtain each currently active landmark point
       Eigen::Matrix<double, 3, 1> pos = landmark.second->Pos();//Obtain the 3D coordinates of the road marking point
        glColor3f(red[0], red[1], red[2]);
        glVertex3d(pos[0], pos[1], pos[2]);
    }
    glEnd();
1.3.1.1.6 advanced operation
1.3.1.1.6.1 set temporary origin
  • My own name is the temporary origin, because it does not change the real origin and can be restored to the original. If you do not understand it correctly, please point out more
  • The main function is: after the implementation, the positions are drawn with the temporary origin as the center, and will be automatically transferred to the original center
  • Usage: it is easier to draw things in this way after knowing the changing camera position and posture
  • Compact version required code
    glPushMatrix();//Must, similar to flag

    Sophus::Matrix4f m = Twc.matrix().template cast<float>();//The acceptable pose format is defined as 4 * 4 matrix
    glMultMatrixf((GLfloat*)m.data());//Set origin
    
	//, omitted here, similar to 1.3.1.1.5.1 and 1.3.1.1.5.2
	
    glPopMatrix();//Delete this temporary origin
}
  • Full version code
void Viewer::DrawFrame(Frame::Ptr frame, const float* color) {
    SE3 Twc = frame->Pose().inverse();//The position and pose of the camera in the world coordinate system are obtained here
    const float sz = 1.0;//depth
    const int line_width = 2.0;//line width
    //Camera internal reference
    const float fx = 400;
    const float fy = 400;
    const float cx = 512;
    const float cy = 384;
    const float width = 1080;
    const float height = 768;

    glPushMatrix();//Must, similar to flag

    Sophus::Matrix4f m = Twc.matrix().template cast<float>();//The acceptable pose format is defined as 4 * 4 matrix
    glMultMatrixf((GLfloat*)m.data());//Set origin

    if (color == nullptr) {
        glColor3f(1, 0, 0);
    } else
        glColor3f(color[0], color[1], color[2]);

    glLineWidth(line_width);
    glBegin(GL_LINES);
    glVertex3f(0, 0, 0);
    glVertex3f(sz * (0 - cx) / fx, sz * (0 - cy) / fy, sz);
    glVertex3f(0, 0, 0);
    glVertex3f(sz * (0 - cx) / fx, sz * (height - 1 - cy) / fy, sz);
    glVertex3f(0, 0, 0);
    glVertex3f(sz * (width - 1 - cx) / fx, sz * (height - 1 - cy) / fy, sz);
    glVertex3f(0, 0, 0);
    glVertex3f(sz * (width - 1 - cx) / fx, sz * (0 - cy) / fy, sz);

    glVertex3f(sz * (width - 1 - cx) / fx, sz * (0 - cy) / fy, sz);
    glVertex3f(sz * (width - 1 - cx) / fx, sz * (height - 1 - cy) / fy, sz);

    glVertex3f(sz * (width - 1 - cx) / fx, sz * (height - 1 - cy) / fy, sz);
    glVertex3f(sz * (0 - cx) / fx, sz * (height - 1 - cy) / fy, sz);

    glVertex3f(sz * (0 - cx) / fx, sz * (height - 1 - cy) / fy, sz);
    glVertex3f(sz * (0 - cx) / fx, sz * (0 - cy) / fy, sz);

    glVertex3f(sz * (0 - cx) / fx, sz * (0 - cy) / fy, sz);
    glVertex3f(sz * (width - 1 - cx) / fx, sz * (0 - cy) / fy, sz);

    glEnd();
    glPopMatrix();//Delete this temporary origin
}
1.3.1.1.6.2 reset a new perspective
    SE3 Twc = current_frame_->Pose().inverse();// Pose of SE3 format
    pangolin::OpenGlMatrix m(Twc.matrix());//The definition still needs a matrix form of 4 * 4
    vis_camera.Follow(m, true);

1.3.2 use of pangolin in multithreading

2 reference articles

Tags: OpenCV AI

Posted by herbally on Thu, 18 Aug 2022 16:59:37 +0300