1 点云点选
- 同时按下shift键和鼠标左键选择点云
- 主要是利用registerPointPickingCallback来对点云上的点进行选择
- 这里是设置了选择6的点生成矩形框(为什么是6个点,因为≤3个点时0BB框只是框选了一个平面,而且点选不是很灵敏有时点了它不显示所以多选一点也好,这个点数也可以自己设置)
2 点云框选
- 按下x键可对点云进行框选,再次按x退出框选模式
- 主要是利用setShapeRenderingProperties来对点云上的区域进行选择
- 可以自己定义一些颜色为片选区域的点云赋色,并将已经框选的区域设为不可再次框选
- 优点是框选比较方便,缺点是会选中框选射线区域内所有的点云
- 对于可以用俯视图来标注的道路交通点云还好,对于不能单从一个视角来标注的就有些麻烦
- point-cloud-annotation-tool用的大概就是这个方法,不过它可以调整标注框的大小还是很方便的
3 其他操作
- 这些都是pcl vtk里的交互风格
- shit+鼠标左键拖动点云可以实现对点云的平移
- ctrl+鼠标左键拖动点云可以实现对点云的旋转
- +、-号可以实现点云点的放大缩小
- 按q退出
4 生成标注框
- 利用每次点选和框选的点云生成AABB(绿色)以及OBB(红色)包围框
- 并且在项目路径下分别保存每个AABB框和OBB框的长宽高以及几何中心坐标x,y,z
5 效果图
下图可以看出框选区域射线范围内点云都被选中
保存AABB和OBB框的长宽高和中心点坐标信息
6 完整代码
#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/common/common.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/features/moment_of_inertia_estimation.h>
#include <fstream>
#include <vector>
using namespace std;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
//pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
PointCloudT::Ptr cloud(new PointCloudT);
boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("PointCloudLabel"));
int num = 0;
vector<PointT> v;
vector<vector<float>> AABB1;
vector<vector<float>> OBB1;
PointT p;
vector<float> p1;
vector<float> p2;
//定义颜色数组用于可视化
float colors[] = {
255, 0, 0, // red 1
0, 255, 0, // green 2
0, 0, 255, // blue 3
255, 255, 0, // yellow 4
0, 255, 255, // light blue5
255, 0, 255, // magenta 6
255, 255, 255, // white 7
255, 128, 0, // orange 8
255, 153, 255, // pink 9
51, 153, 255, // 10
153, 102, 51, // 11
128, 51, 153, // 12
153, 153, 51, // 13
163, 38, 51, // 14
204, 153, 102, // 15
204, 224, 255, // 16
128, 179, 255, // 17
206, 255, 0, // 18
255, 204, 204, // 19
204, 255, 153, // 20
34, 139, 34,
139, 101, 8,
131, 111, 255,
99, 184, 255,
0, 255, 127,
82, 139, 139,
};
//计算点云密度
float Density(pcl::PointCloud<pcl::PointXYZ>::Ptr incloud, int k)
{
pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; //创建一个快速k近邻查询,查询的时候若该点在点云中,则第一个近邻点是其本身
kdtree.setInputCloud(incloud);
//int k = 100;
float everagedistance = 0;
for (int i = 0; i < incloud->size() / 2; i++)
{
vector<int> nnh;
vector<float> squaredistance;
// pcl::PointXYZ p;
// p = cloud->points[i];
kdtree.nearestKSearch(incloud->points[i], k, nnh, squaredistance);
everagedistance += sqrt(squaredistance[1]);
// cout<<everagedistance<<endl;
}
everagedistance = everagedistance / (incloud->size() / 2);
//cout << "everage distance is : " << everagedistance << endl;
return everagedistance;
}
void WriteAABB()
{
ofstream out("AABB.txt");
for (vector<vector<float>> ::iterator it = AABB1.begin(); it != AABB1.end(); ++it)
{
out << (*it)[0] << " " << (*it)[1] << " " << (*it)[2] << " "
<< (*it)[3] << " " << (*it)[4] << " " << (*it)[5] << endl;
}
}
void WriteOBB()
{
ofstream out("OBB.txt");
for (vector<vector<float>> ::iterator it = OBB1.begin(); it != OBB1.end(); ++it)
{
out << (*it)[0] << " " << (*it)[1] << " " << (*it)[2] << " "
<< (*it)[3] << " " << (*it)[4] << " " << (*it)[5] << endl;
}
}
int a = 0, b = 0, c = 1;
void WriteBox(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
{
p1.clear();
p2.clear();
//pcl::PointCloud<pcl::PointXYZ> cloud1;
pcl::MomentOfInertiaEstimation <pcl::PointXYZ> feature_extractor;//实例化一个对象
feature_extractor.setInputCloud(cloud);//设置输入点云
feature_extractor.compute();//开始特征计算
std::vector <float> moment_of_inertia;//存放惯性距的特征向量
std::vector <float> eccentricity;//存放偏心率的特征向量
pcl::PointXYZ min_point_AABB;
pcl::PointXYZ max_point_AABB;
pcl::PointXYZ min_point_OBB;
pcl::PointXYZ max_point_OBB;
pcl::PointXYZ position_OBB;
Eigen::Matrix3f rotational_matrix_OBB;
float major_value, middle_value, minor_value;
Eigen::Vector3f major_vector, middle_vector, minor_vector;
Eigen::Vector3f mass_center;
feature_extractor.getMomentOfInertia(moment_of_inertia);//计算出的惯性矩
feature_extractor.getEccentricity(eccentricity);//计算出的偏心率
feature_extractor.getAABB(min_point_AABB, max_point_AABB);//计算轴对称边界盒子
feature_extractor.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);//OBB对应的相关参数
feature_extractor.getEigenValues(major_value, middle_value, minor_value);//三个特征值
feature_extractor.getEigenVectors(major_vector, middle_vector, minor_vector);//三个特征向量
feature_extractor.getMassCenter(mass_center);//计算质心
//viewer->addCoordinateSystem(1.0);
//viewer->resetCamera();
//viewer->initCameraParameters();
std::stringstream ss;
std::string OBB;
ss << a++;
ss >> OBB;
OBB += "_OBB";
std::stringstream ss1;
std::string AABB;
ss1 << b++;
ss1 >> AABB;
AABB += "_AABB";
//pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>(cloud, 0, 255, 0),
//viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "happy"+a);
viewer->addCube(min_point_AABB.x, max_point_AABB.x, min_point_AABB.y, max_point_AABB.y, min_point_AABB.z, max_point_AABB.z, 0.0, 1.0, 0.0, AABB);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.1, AABB);//图形的不透明度
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH, 4, AABB);//线宽
Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
std::cout << "---第 " << c << " 个框---" << std::endl;
std::cout << "size of cloud :" << cloud->points.size() << endl;
std::cout << "position_OBB: " << position_OBB << endl;
//std::cout << "mass_center: " << mass_center << endl;//中心坐标
Eigen::Quaternionf quat(rotational_matrix_OBB);
// position:中心位置;quat:旋转矩阵
viewer->addCube(position, quat, max_point_OBB.x - min_point_OBB.x, max_point_OBB.y - min_point_OBB.y, max_point_OBB.z - min_point_OBB.z, OBB);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, 1, 0, 0, OBB);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 0.1, OBB);
viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_LINE_WIDTH, 4, OBB);
viewer->setRepresentationToWireframeForAllActors();//将所有actor的可视化表示更改为线框表示
pcl::PointXYZ center(mass_center(0), mass_center(1), mass_center(2));
// 获取主轴major_vector,中轴middle_vector,辅助轴minor_vector
pcl::PointXYZ x_axis(major_vector(0) + mass_center(0), major_vector(1) + mass_center(1), major_vector(2) + mass_center(2));
pcl::PointXYZ y_axis(middle_vector(0) + mass_center(0), middle_vector(1) + mass_center(1), middle_vector(2) + mass_center(2));
pcl::PointXYZ z_axis(minor_vector(0) + mass_center(0), minor_vector(1) + mass_center(1), minor_vector(2) + mass_center(2));
//viewer->addLine(center, x_axis, 1.0f, 0.0f, 0.0f, "major eigen vector");
//viewer->addLine(center, y_axis, 0.0f, 1.0f, 0.0f, "middle eigen vector");
//viewer->addLine(center, z_axis, 0.0f, 0.0f, 1.0f, "minor eigen vector");
//std::cout << "moment_of_inertia :" << moment_of_inertia.size() << endl;
//std::cout << "eccentricity :" << eccentricity.size() << endl;
std::cout << "OBB:center :" << center << endl;
std::cout << "OBB:长宽高:(" << max_point_OBB.x - min_point_OBB.x << ", " << max_point_OBB.y - min_point_OBB.y << ", " << max_point_OBB.z - min_point_OBB.z << ")" << endl;
std::cout << "AABB:center;(" << (min_point_AABB.x + max_point_AABB.x) / 2 << "," << (min_point_AABB.y + max_point_AABB.y) / 2 << "," << (min_point_AABB.z + max_point_AABB.z) / 2 << ")" << endl;
std::cout << "AABB:长宽高:(" << max_point_AABB.x - min_point_AABB.x << "," << max_point_AABB.y - min_point_AABB.y << "," << max_point_AABB.z - min_point_AABB.z << ")" << endl;
//std::cout << "center :(" << (max_point_OBB.x- min_point_OBB.x)/2
// << ","<< (max_point_OBB.y - min_point_OBB.y) / 2
// << "," << (max_point_OBB.z - min_point_OBB.z) / 2 <<")"<< endl;
//cloud1 = *cloud;
p1.push_back(max_point_AABB.x - min_point_AABB.x);
p1.push_back(max_point_AABB.y - min_point_AABB.y);
p1.push_back(max_point_AABB.z - min_point_AABB.z);
p1.push_back((min_point_AABB.x + max_point_AABB.x) / 2);
p1.push_back((min_point_AABB.y + max_point_AABB.y) / 2);
p1.push_back((min_point_AABB.z + max_point_AABB.z) / 2);
AABB1.push_back(p1);
p2.push_back(max_point_OBB.x - min_point_OBB.x);
p2.push_back(max_point_OBB.y - min_point_OBB.y);
p2.push_back(max_point_OBB.z - min_point_OBB.z);
p2.push_back(center.x);
p2.push_back(center.y);
p2.push_back(center.z);
OBB1.push_back(p2);
cloud->clear();
c++;
//v.clear();
}
int i = 0;
unsigned char *pointmark;//点云分类标记
void pp_callback_AreaSelect(const pcl::visualization::AreaPickingEvent& event, void* args)
{
pcl::PointCloud<PointT>::Ptr clicked_points_3d(new PointCloudT);
//存储索引
vector< int > indices;
if (event.getPointsIndices(indices) == -1)
return;
for (int i = 0; i < indices.size(); ++i)
{
if (pointmark[indices[i]] == 0)
{
clicked_points_3d->points.push_back(cloud->points.at(indices[i]));
a++;
pointmark[indices[i]] = 1;//将点云标记为已圈选状态
}
}
pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(clicked_points_3d, colors[i * 3], colors[i * 3 + 1], colors[i * 3 + 2]);
std::stringstream ss2;
std::string cloudName;
ss2 << num++;
ss2 >> cloudName;
cloudName += "_cloudName";
viewer->addPointCloud(clicked_points_3d, red, cloudName);
//viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, cloudName);
WriteBox(clicked_points_3d);
//保存点云
//pcl::io::savePCDFileBinary(cloudName += ".pcd", *clicked_points_3d);
i++;
//std::cout << "第 " << i << " 个类别" << std::endl;
//std::cout << "该类点数:" << a << std::endl;
}
pcl::PointCloud<PointT>::Ptr clicked_points_3d1(new PointCloudT);
void
pp_callback_PointsSelect(const pcl::visualization::PointPickingEvent& event, void* args)
{
if (event.getPointIndex() == -1)
return;
PointT current_point;
event.getPoint(current_point.x, current_point.y, current_point.z);
//将选中的点云存在Points里面
clicked_points_3d1->points.push_back(current_point);
// 将选中的点赋为红色
pcl::visualization::PointCloudColorHandlerCustom<PointT> red(clicked_points_3d1, 255, 0, 0);
viewer->removePointCloud("clicked_points");
viewer->addPointCloud(clicked_points_3d1, red, "clicked_points");
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "clicked_points");
//std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;
p.x = current_point.x;
p.y = current_point.y;
p.z = current_point.z;
//v.push_back(p);
if (clicked_points_3d1->size() > 5)
{
WriteBox(clicked_points_3d1);
}
}
//void boxForCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud)
//{
// //pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
// //if (pcl::io::loadPCDFile("F:/information/car_0001.pcd", *cloud) == -1)
// // return (-1);
//
//
//}
void main()
{
float density = 0;
std::string filename("../rabbit.pcd");
if (pcl::io::loadPCDFile(filename, *cloud))
{
std::cerr << "ERROR: Cannot open file " << filename << "! Aborting..." << std::endl;
return;
}
//getMinMax3D用到的头文件#include <pcl/common/common.h>
pcl::PointXYZ p_min , p_max ;
pcl::getMinMax3D(*cloud, p_min, p_max);
density = Density(cloud, 50);
std::cout << "点云点数:" << cloud->points.size() << std::endl;
std::cout << "点云密度:" << density << std::endl;
std::cout <<"min:"<< p_min << " max:" << p_max << std::endl;
pointmark = new unsigned char[cloud->size()];
for (size_t i = 0; i < cloud->size(); i++)
{
pointmark[i] = 0;//初始化点云分类标识,0为未标记点
}
//viewer->addPointCloud(cloud, "bunny");
viewer->setBackgroundColor(0, 0, 0);
viewer->addPointCloud<pcl::PointXYZ>(cloud, "sample cloud");
//viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "sample cloud");
viewer->resetCamera();
//viewer->setCameraPosition(0, 0, -2, 0, -1, 0, 0);
viewer->registerPointPickingCallback(pp_callback_PointsSelect, (void*)&cloud);
viewer->registerAreaPickingCallback(pp_callback_AreaSelect, (void*)&cloud);
std::cout << "Shift+click on points" << std::endl;
std::cout << "press x to chose the area" << std::endl;
viewer->spin();
WriteAABB();//写出点数据
WriteOBB();
std::cout << "done." << std::endl;
while (!viewer->wasStopped())
{
viewer->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
}
————————————————
版权声明:本文为CSDN博主「树和猫」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_68312479/article/details/126312813