viz模块主要用于3D可视化显示
与pangolin相比:缺点,不容易添加控件(按钮,滑动条等) ;优点,简单调试方便.
-
创建一个窗口并显示坐标系
首先看个简单示例程序,创建一个窗口并显示坐标系:
//创建可视化窗口
viz::Viz3d window1("window1");
//构造一个坐标系,并显示到窗口中
window1.showWidget("Coordinate", viz::WCoordinateSystem());
//开启永久循环暂留
window1.spin();
第一句,创建窗口。
很简单,类型为Viz3d类型,参数为窗口名称。
第二句,在窗口中显示部件。
viz模块中,窗口内显示的一切东西通通为部件,也就是Widget,这里调用showWidget()函数,将部件显示在窗口中。
来看一下showWidget()定义:
/** @brief Shows a widget in the window.
@param id A unique id for the widget. @param widget The widget to be displayed in the window.
@param pose Pose of the widget.
*/
void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity());
看看三个参数:
&id:这个参数是为了给部件定义一个unique名称,用于后面定位到此部件,并不是想当然的认为是窗口中部件的名称(类似于坐标轴的名字一样,运行发现窗口中除了坐标轴,并没有名称)。
&widget:自然就是要显示的部件了。这是用viz::WCoordinateSystem()直接当场创建了一个坐标系部件,WCoordinateSystem类是继承自Widget3D类,所以本质类型也是部件,可以在窗口中显示。
后面还有一个带有默认值的pose参数,示例程序中没有传入此参数,采用的默认值,关于Affine3d后面再说。
第三句,永久循环暂留。
spin()函数开启一个event loop永远循环。直观的用处就是让画面停在那里,如果没有这一句的话,画面基本就是秒闪一下然后消失了。
关于spin()函数有两点要说:
第一就是spin()真的会让程序停在那里,不会运行下方的语句,除非按q或者e建,才会继续走。
第二就是这个函数的变种:void spinOnce(int time = 1, bool force_redraw = false); 表示event loop循环time时间,也就是在词句的停留时间,time的单位为毫秒,第二个force_redraw还不知道有啥用,测试来看,没有区别。后面有这个函数的示例程序。
OK,下面就是这个最简单窗口的运行结果: [cmakeList libopencv_viz.so]
viz::Viz3d myWindow("Coordinate Frame"); /*创建一个可视化窗口*/
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());/*窗口的坐标系相对关系 XYZ-> RGB;*/


XYZ-> RGB (右手系:X红->右,Y绿->上;Z蓝黑->外);
#include <iostream>
#include <fstream>
#include <opencv2/viz.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
using namespace std;
using namespace cv;
// EXP 2: 将坐标系绕Y轴旋转并循环显示
int main()
{
viz::Viz3d window("window");
//创建一个1*3的rotation vector
Mat rvec = Mat::zeros(1, 3, CV_32F);//循环外,全局变量
//动画的本质:调整部件位姿并循环显示,控制条件是窗口没被停止,也就是主动按下了q或者e键
while (!window.wasStopped()) {
rvec.at<float>(0, 0) = 0.f;
rvec.at<float>(0, 1) += CV_PI * 0.01f; // Y轴旋转
rvec.at<float>(0, 2) = 0.f;
Mat rmat;
//罗德里格斯公式,将罗德里格斯向量转换成旋转矩阵
Rodrigues(rvec, rmat);
//构造仿射变换类型的pose,这个类型暂且看做OpenCV中的位姿类型,两个Mat参数,一个旋转,一个平移
Affine3f pose(rmat, Vec3f(0, 0, 0));
//这一句就是整个可视化窗口能够动起来的核心语句了,
//说白了就是利用循环来不断调整上面坐标系部件的位姿,达到动画的效果
//另外这里就利用到了坐标系的ID,来表征调整的是坐标系的位姿
window.showWidget("Coordinate", viz::WCoordinateSystem(), pose);
//控制单帧暂留时间,调整time参数的效果就是平面转的快慢,本质上就是每一个位姿的停留显示时间。
window.spinOnce(1, false);
}
return 0;
}
-
创建平面类
好,再来加点东西:
viz::Viz3d window("window");
window.showWidget("Coordinate", viz::WCoordinateSystem());
viz::WPlane plane;
window.showWidget("plane", plane);
window.spin();
WPlane即为平面类,也是继承自Widget3D类。这里创建一个平面部件(各种参数都不写了,用默认值),添加到窗口中,画面如下:
OK,多了个白色正方形平面。
int main()
{
// viz::Viz3d window("window");
// window.showWidget("Coordinate", viz::WCoordinateSystem());
// viz::WPlane plane;
// window.showWidget("plane", plane);
// window.spin();
viz::Viz3d window("window");
window.showWidget("Coordinate", viz::WCoordinateSystem());
viz::WPlane plane; //创建平面
window.showWidget("plane", plane);//添加平面,并设置一个ID为plane
Mat rvec = Mat::zeros(1, 3, CV_32F); //创建一个1*3的rotation vector
//动画的本质:调整部件位姿并循环显示,控制条件是窗口没被停止,也就是主动按下了q或者e键
while(!window.wasStopped())
{
rvec.at<float>(0, 0) = 0.f;
rvec.at<float>(0, 1) += CV_PI * 0.01f;
rvec.at<float>(0, 2) = 0.f;
Mat rmat;
//罗德里格斯公式,将罗德里格斯向量转换成旋转矩阵
Rodrigues(rvec, rmat);
//构造仿射变换类型的pose,这个类型暂且看做OpenCV中的位姿类型,两个参数,一个旋转,一个平移
Affine3f pose(rmat, Vec3f(0, 0, 0));
//这一句就是整个可视化窗口能够动起来的核心语句了,
//说白了就是利用循环来不断调整上面plane部件的位姿,达到动画的效果
//另外这里就利用到了平面的ID,来表征调整的是平面的位姿
window.setWidgetPose("plane", pose);
//控制单帧暂留时间,调整time参数的效果就是平面转的快慢,本质上就是每一个位姿的停留显示时间。
window.spinOnce(1, false);
}
return 0;
}
主要的区别就是下方多了一个循环。
定义一个旋转向量rvec,然后调用Rodrigues()函数将其转换成旋转矩阵rmat,再用rmat构造pose,最后用setWidgetPose()函数和构造的pose,来达到调整部件位姿的效果,循环执行后的结果就是看起来平面转起来了。
这里说一下Affine3f类型的 pose参数,Affine3是一个3维仿射变换类,先摆上构造函数源码:
Affine3();
//! Augmented affine matrix
Affine3(const Mat4& affine);
//! Rotation matrix
Affine3(const Mat3& R, const Vec3& t = Vec3::all(0));
//! Rodrigues vector
Affine3(const Vec3& rvec, const Vec3& t = Vec3::all(0));
//! Combines all contructors above. Supports 4x4, 4x3, 3x3, 1x3, 3x1 sizes of data matrix
explicit Affine3(const Mat& data, const Vec3& t = Vec3::all(0));
//! From 16th element array
explicit Affine3(const float_type* vals);
默认构造函数不用说了。看其他构造函数很容易发现,其实它就是一个变换T,此处用于表征位姿。构造函数就多种多样了:直接4*4矩阵构造、旋转向量和平移向量构造、旋转矩阵和平移向量构造、开放式构造(也就是旋转向量部分随你用什么矩阵了)、16元素的数组构造。示例中用的是开放式构造。
构造好了位姿,利用循环和window.setWidgetPose(“plane”, pose);这句,不断调整部件的pose数据,最终画面就动起来了。由于不能传动图,所以只能传个截图,白色平面会绕着绿色坐标轴右方向转动:
-
创建3D点云
单个3D点的画法:
// EXP 4: 将单个3D点显示
int main(){
viz::Viz3d myWindow("Coordinate Frame"); /*创建一个可视化窗口*/
myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem());/*窗口的坐标系相对关系 XYZ-> RGB; 右手系 */
Mat cloud0(1, 1, CV_32FC3);
cloud0.at<float>(0,0)=4.0f;
cloud0.at<float>(0,1)=4.0f;
cloud0.at<float>(0,1)=4.0f;
viz::WCloud cloud_widget(cloud0, viz::Color::green());
myWindow.showWidget("simple_cloud", cloud_widget);
myWindow.spin();
return 0;
}

多个3D点云画法
// EXP 4: 将多个3D点云显示,读取.ply文件并转Mat
#include <opencv2/viz.hpp>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
static void help()
{


2862

被折叠的 条评论
为什么被折叠?



