(1)HelloPangolin
第一个Pangolin程序
#include <pangolin/pangolin.h>
int main( int /*argc*/, char** /*argv*/ )
{
// 创建名称为“Main”的GUI窗口,尺寸为640×640
pangolin::CreateWindowAndBind("Main",640,480);
// 启动深度测试
glEnable(GL_DEPTH_TEST);
// 创建一个观察相机视图
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(640,480,420,420,320,320,0.2,100),
pangolin::ModelViewLookAt(2,0,2, 0,0,0, pangolin::AxisY)
);
// 创建交互视图
pangolin::Handler3D handler(s_cam); //交互相机视图句柄
pangolin::View& d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
.SetHandler(&handler);
while( !pangolin::ShouldQuit() )
{
// 清空颜色和深度缓存
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam);
// 在原点绘制一个立方体
pangolin::glDrawColouredCube();
// 绘制坐标系
glLineWidth(3);
glBegin ( GL_LINES );
glColor3f ( 0.8f,0.f,0.f );
glVertex3f( -1,-1,-1 );
glVertex3f( 0,-1,-1 );
glColor3f( 0.f,0.8f,0.f);
glVertex3f( -1,-1,-1 );
glVertex3f( -1,0,-1 );
glColor3f( 0.2f,0.2f,1.f);
glVertex3f( -1,-1,-1 );
glVertex3f( -1,-1,0 );
glEnd();
// 运行帧循环以推进窗口事件
pangolin::FinishFrame();
}
return 0;
}
思考一下自己如何记忆框架步骤可以自己记下代码并能独立写出。
1)计算机桌面的显示视图
//1.创建一个窗口
pangolin::CreateWindowAndBind("window_title", 640, 480); //w=1000 h=600
//2.启用深度测试
glEnable(GL_DEPTH_TEST);
2)相机
图形建立起来后,可以通过相机观察,那么观察的相机的内参以及相机位置则是关键。
//3.创建一个观察相机视图(定义目标并初始化)
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100), //配置相机内参
//内参依次为相机的图像高度,宽度,4个相机内参,最近最远视距
pangolin::ModelViewLookAt(2,0,2, 0,0,0,pangolin::AxisY)
//相机所在坐标x,y,z 视点所在坐标x,y,z, y轴为正方向
);
3)相机拍到的图像
//4.创建交互视图
pangolin::Handler3D handler(s_cam);
pangolin::View& d_cam = pangolin::CreateDisplay().SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f).SetHandler(&handler);
//视图在视图内的的范围(上,下,左,右,长宽比) 比值0:最下端 比值1:最上端
4)绘制图形
while (!pangolin::ShouldQuit()) {
//5.清空颜色和深度缓存,如果不清空则会保留上一帧图形
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam); //个人理解:将相机加载到视图上
// 在原点绘制一个立方体
pangolin::glDrawColouredCube();
// 绘制坐标系
glLineWidth(3);
glBegin ( GL_LINES );
glColor3f ( 0.8f,0.f,0.f );
glVertex3f( -1,-1,-1 );
glVertex3f( 0,-1,-1 );
glColor3f( 0.f,0.8f,0.f);
glVertex3f( -1,-1,-1 );
glVertex3f( -1,0,-1 );
glColor3f( 0.2f,0.2f,1.f);
glVertex3f( -1,-1,-1 );
glVertex3f( -1,-1,0 );
glEnd();
pangolin::FinishFrame();
}
(2)多线程
在 HelloPangolin 中,在主线程中创建了视窗、视图并绘制了对应的图像,但在更多的应用中,出于效率考虑,可视化部分内容通常单独运行在一个线程中。
#include <pangolin/pangolin.h>
#include <thread>
static const std::string window_name = "HelloPangolinThreads";
void setup() {
// create a window and bind its context to the main thread
pangolin::CreateWindowAndBind(window_name, 640, 480);
// enable depth
glEnable(GL_DEPTH_TEST);
// unset the current context from the main thread
pangolin::GetBoundWindow()->RemoveCurrent();
}
void run() {
// fetch the context and bind it to this thread
pangolin::BindToContext(window_name);
// we manually need to restore the properties of the context
glEnable(GL_DEPTH_TEST);
// Define Projection and initial ModelView matrix
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
pangolin::ModelViewLookAt(-2,2,-2, 0,0,0, pangolin::AxisY)
);
// Create Interactive View in window
pangolin::Handler3D handler(s_cam);
pangolin::View& d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
.SetHandler(&handler);
while( !pangolin::ShouldQuit() )
{
// Clear screen and activate view to render into
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam);
// Render OpenGL Cube
pangolin::glDrawColouredCube();
// Swap frames and Process Events
pangolin::FinishFrame();
}
// unset the current context from the main thread
pangolin::GetBoundWindow()->RemoveCurrent();
}
int main( int /*argc*/, char** /*argv*/ )
{
// create window and context in the main thread
setup();
// use the context in a separate rendering thread
std::thread render_loop;
render_loop = std::thread(run);
render_loop.join();
return 0;
}
1)主线程:桌面窗口创建 setup()
void setup() {
// create a window and bind its context to the main thread
pangolin::CreateWindowAndBind(window_name, 640, 480);
// enable depth
glEnable(GL_DEPTH_TEST);
// unset the current context from the main thread
// 在主线程调用完后,使用GetBoundWindow()->RemoveCurrent()将其解绑
pangolin::GetBoundWindow()->RemoveCurrent();
}
2)另一个线程:
void run() {
// fetch the context and bind it to this thread
// BindToContext()函数将之前解绑的视窗绑定到当前线程
pangolin::BindToContext(window_name);
// we manually need to restore the properties of the context
glEnable(GL_DEPTH_TEST);
// Define Projection and initial ModelView matrix
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(640,480,420,420,320,240,0.2,100),
pangolin::ModelViewLookAt(-2,2,-2, 0,0,0, pangolin::AxisY)
);
// Create Interactive View in window
pangolin::Handler3D handler(s_cam);
pangolin::View& d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, 0.0, 1.0, -640.0f/480.0f)
.SetHandler(&handler);
while( !pangolin::ShouldQuit() )
{
// Clear screen and activate view to render into
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam);
// Render OpenGL Cube
pangolin::glDrawColouredCube();
// Swap frames and Process Events
pangolin::FinishFrame();
}
// unset the current context from the main thread
pangolin::GetBoundWindow()->RemoveCurrent();
}
3)
int main( int /*argc*/, char** /*argv*/ )
{
// create window and context in the main thread
setup();
// use the context in a separate rendering thread
std::thread render_loop;
render_loop = std::thread(run);
render_loop.join();
return 0;
}
(3)Pangolin添加控件
1)分割视窗
SetBounds()
函数:View& SetBounds(Attach bottom, Attach top, Attach left, Attach right, double aspect);
// 分割视窗
const int UI_WIDTH = 180;
// 右侧用于显示视口
pangolin::View& d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, pangolin::Attach::Pix(UI_WIDTH), 1.0, -640.0f/480.0f)
.SetHandler(new pangolin::Handler3D(s_cam));
// 左侧用于创建控制面板
pangolin::CreatePanel("ui")
.SetBounds(0.0, 1.0, 0.0, pangolin::Attach::Pix(UI_WIDTH));
2)面板控件对象
// 创建控制面板的控件对象,pangolin中
pangolin::Var<bool> A_Button("ui.a_button", false, false); // 按钮
pangolin::Var<bool> A_Checkbox("ui.a_checkbox", false, true); // 选框
pangolin::Var<double> Double_Slider("ui.a_slider", 3, 0, 5); //double滑条
pangolin::Var<int> Int_Slider("ui.b_slider", 2, 0, 5); //int滑条
pangolin::Var<std::string> A_string("ui.a_string", "Hello Pangolin");
pangolin::Var<bool> SAVE_IMG("ui.save_img", false, false); // 按钮
pangolin::Var<bool> SAVE_WIN("ui.save_win", false, false); // 按钮
pangolin::Var<std::function<void()>> reset("ui.Reset", SampleMethod);//
#include <pangolin/pangolin.h>
#include <string>
#include <iostream>
// ----------------------------------------------------------------- //
void SampleMethod()
{
std::cout << "You typed ctrl-r or pushed reset" << std::endl;
// std::cout << "Window width: " << i << std::endl;
}
// ----------------------------------------------------------------------- //
int main(/*int argc, char* argv[]*/)
{
// 创建视窗
pangolin::CreateWindowAndBind("Main",640,480);
// 启动深度测试
glEnable(GL_DEPTH_TEST);
// 创建一个摄像机
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(640,480,420,420,320,240,0.1,1000),
pangolin::ModelViewLookAt(-0,0.5,-3, 0,0,0, pangolin::AxisY)
);
// 分割视窗
const int UI_WIDTH = 180;
// 右侧用于显示视口
pangolin::View& d_cam = pangolin::CreateDisplay()
.SetBounds(0.0, 1.0, pangolin::Attach::Pix(UI_WIDTH), 1.0, -640.0f/480.0f)
.SetHandler(new pangolin::Handler3D(s_cam));
// 左侧用于创建控制面板
pangolin::CreatePanel("ui")
.SetBounds(0.0, 1.0, 0.0, pangolin::Attach::Pix(UI_WIDTH));
// 创建控制面板的控件对象,pangolin中
pangolin::Var<bool> A_Button("ui.a_button", false, false); // 按钮
pangolin::Var<bool> A_Checkbox("ui.a_checkbox", false, true); // 选框
pangolin::Var<double> Double_Slider("ui.a_slider", 3, 0, 5); //double滑条
pangolin::Var<int> Int_Slider("ui.b_slider", 2, 0, 5); //int滑条
pangolin::Var<std::string> A_string("ui.a_string", "Hello Pangolin");
pangolin::Var<bool> SAVE_IMG("ui.save_img", false, false); // 按钮
pangolin::Var<bool> SAVE_WIN("ui.save_win", false, false); // 按钮
pangolin::Var<std::function<void()>> reset("ui.Reset", SampleMethod);//
// 绑定键盘快捷键
// Demonstration of how we can register a keyboard hook to alter a Var
pangolin::RegisterKeyPressCallback(pangolin::PANGO_CTRL + 'b', pangolin::SetVarFunctor<double>("ui.a_slider", 3.5));
// Demonstration of how we can register a keyboard hook to trigger a method
pangolin::RegisterKeyPressCallback(pangolin::PANGO_CTRL + 'r', SampleMethod);
// Default hooks for exiting (Esc) and fullscreen (tab).
while( !pangolin::ShouldQuit() )
{
// Clear entire screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 各控件的回调函数
if(pangolin::Pushed(A_Button))
std::cout << "Push button A." << std::endl;
if(A_Checkbox)
Int_Slider = Double_Slider;
// 保存整个win
if( pangolin::Pushed(SAVE_WIN) )
pangolin::SaveWindowOnRender("window");
// 保存view
if( pangolin::Pushed(SAVE_IMG) )
d_cam.SaveOnRender("cube");
// glColor3f(1.0,0.0,1.0);
pangolin::glDrawColouredCube();
// Swap frames and Process Events
pangolin::FinishFrame();
}
return 0;
}
(4)绘制运动轨迹
#include <pangolin/pangolin.h>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <unistd.h>
#include <iostream>
#include <fstream>
std::string trajectory_file = "../trajectory.txt";
void DrawTrajectory(std::vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> poses);
int main(int argc, char const *argv[])
{
std::vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> poses;
std::ifstream fin(trajectory_file);
if (!fin)
{
std::cout << "can not find file at " << trajectory_file << std::endl;
return 1;
}
while (!fin.eof())
{
double time, tx, ty, tz, qx, qy, qz, qw;
fin >> time
>> tx
>> ty
>> tz
>> qx
>> qy
>> qz
>> qw;
Eigen::Isometry3d Twr(Eigen::Quaterniond(qw, qx, qy, qz));
Twr.pretranslate(Eigen::Vector3d(tx, ty, tz));
poses.push_back(Twr);
}
std::cout << "read total " << poses.size() << std::endl;
DrawTrajectory(poses);
return 0;
}
void DrawTrajectory(std::vector<Eigen::Isometry3d, Eigen::aligned_allocator<Eigen::Isometry3d>> poses)
{
pangolin::CreateWindowAndBind("Trajectory Viewer", 1024, 768);
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
pangolin::OpenGlRenderState s_cam(
pangolin::ProjectionMatrix(1024, 768, 500, 500, 512, 389, 0.1, 1000), //配置相机内参
//内参依次为相机的图像高度,宽度,4个相机内参,最近最远视距
pangolin::ModelViewLookAt(0, -0.1, -1.8, 0, 0, 0, 0.0, -1.0, 0.0)
//相机所在坐标x,y,z 视点所在坐标x,y,z, y轴为正方向
);
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)
);
while (!pangolin::ShouldQuit()) {
//5.清空颜色和深度缓存,如果不清空则会保留上一帧图形
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
d_cam.Activate(s_cam); //个人理解:将相机加载到视图上
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glLineWidth(2);
//绘制坐标系(每个位姿的三个坐标轴)
for (size_t i = 0; i < poses.size(); i++)
{
Eigen::Vector3d Ow = poses[i].translation();
Eigen::Vector3d Xw = poses[i] * (0.1 * Eigen::Vector3d(1, 0, 0));
Eigen::Vector3d Yw = poses[i] * (0.1 * Eigen::Vector3d(0, 1, 0));
Eigen::Vector3d Zw = poses[i] * (0.1 * Eigen::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();
}
for (size_t i = 0; i < poses.size(); i++)
{
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
auto p1 = poses[i];
auto 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();
}
pangolin::FinishFrame();
usleep(5000);
}
}