|
@@ -47,7 +47,7 @@ bool Region_detector::preprocess(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, p
|
|
|
// 离群点过滤
|
|
|
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
|
|
|
sor.setInputCloud(cloud_out);
|
|
|
- sor.setMeanK(4); //K近邻搜索点个数
|
|
|
+ sor.setMeanK(10); //K近邻搜索点个数
|
|
|
sor.setStddevMulThresh(4.0); //标准差倍数
|
|
|
sor.setNegative(false); //保留未滤波点(内点)
|
|
|
sor.filter(*cloud_out); //保存滤波结果到cloud_filter
|
|
@@ -66,10 +66,122 @@ bool Region_detector::findWheelbase()
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-bool Region_detector::clustering(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in){
|
|
|
+double distance(cv::Point2f p1, cv::Point2f p2)
|
|
|
+{
|
|
|
+ return sqrt(pow(p1.x - p2.x, 2.0) + pow(p1.y - p2.y, 2.0));
|
|
|
+}
|
|
|
+bool Region_detector::isRect(std::vector<cv::Point2f>& points)
|
|
|
+{
|
|
|
+ if (points.size() == 4)
|
|
|
+ {
|
|
|
+ double L[3] = {0.0};
|
|
|
+ L[0] = distance(points[0], points[1]);
|
|
|
+ L[1] = distance(points[1], points[2]);
|
|
|
+ L[2] = distance(points[0], points[2]);
|
|
|
+ double max_l = L[0];
|
|
|
+ double l1 = L[1];
|
|
|
+ double l2 = L[2];
|
|
|
+ int max_index = 0;
|
|
|
+ cv::Point2f ps = points[0], pt = points[1];
|
|
|
+ cv::Point2f pc = points[2];
|
|
|
+ for (int i = 1; i < 3; ++i) {
|
|
|
+ if (L[i] > max_l) {
|
|
|
+ max_index = i;
|
|
|
+ max_l = L[i];
|
|
|
+ l1 = L[abs(i + 1) % 3];
|
|
|
+ l2 = L[abs(i + 2) % 3];
|
|
|
+ ps = points[i % 3];
|
|
|
+ pt = points[(i + 1) % 3];
|
|
|
+ pc = points[(i + 2) % 3];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
|
|
|
+ if (fabs(cosa) >= 0.13) {
|
|
|
+ std::cout << " angle cos >0.13 =" << cosa << " i=" << max_index;
|
|
|
+ std::cout << "L1:" << l1 << " L2:" << l2 << " L3:" << max_l;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ float width=std::min(l1,l2);
|
|
|
+ float length=std::max(l1,l2);
|
|
|
+ if(width<1.400 || width >2.000 || length >3.300 ||length < 2.200)
|
|
|
+ {
|
|
|
+ std::cout<<"\t width<1400 || width >2100 || length >3300 ||length < 2100 "
|
|
|
+ <<" length:"<<length<<" width:"<<width;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ double d = distance(pc, points[3]);
|
|
|
+ cv::Point2f center1 = (ps + pt) * 0.5;
|
|
|
+ cv::Point2f center2 = (pc + points[3]) * 0.5;
|
|
|
+ if (fabs(d - max_l) > max_l * 0.1 || distance(center1, center2) > 0.150) {
|
|
|
+ std::cout << "d:" << d << " maxl:" << max_l << " center1:" << center1 << " center2:" << center2
|
|
|
+ << " center distance=" << distance(center1, center2);;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ std::cout << " rectangle verify OK cos angle=" << cosa << " length off=" << fabs(d - max_l)
|
|
|
+ << " center distance=" << distance(center1, center2);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else if(points.size()==3)
|
|
|
+ {
|
|
|
+ double L[3] = {0.0};
|
|
|
+ L[0] = distance(points[0], points[1]);
|
|
|
+ L[1] = distance(points[1], points[2]);
|
|
|
+ L[2] = distance(points[0], points[2]);
|
|
|
+ double max_l = L[0];
|
|
|
+ double l1 = L[1];
|
|
|
+ double l2 = L[2];
|
|
|
+ int max_index = 0;
|
|
|
+ cv::Point2f ps = points[0], pt = points[1];
|
|
|
+ cv::Point2f pc = points[2];
|
|
|
+ for (int i = 1; i < 3; ++i) {
|
|
|
+ if (L[i] > max_l) {
|
|
|
+ max_index = i;
|
|
|
+ max_l = L[i];
|
|
|
+ l1 = L[abs(i + 1) % 3];
|
|
|
+ l2 = L[abs(i + 2) % 3];
|
|
|
+ ps = points[i % 3];
|
|
|
+ pt = points[(i + 1) % 3];
|
|
|
+ pc = points[(i + 2) % 3];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ double cosa = (l1 * l1 + l2 * l2 - max_l * max_l) / (2.0 * l1 * l2);
|
|
|
+ if (fabs(cosa) >= 0.12) {
|
|
|
+ std::cout << "3 wheels angle cos >0.12 =" << cosa << " i=" << max_index;
|
|
|
+ std::cout << "L1:" << l1 << " L2:" << l2 << " L3:" << max_l;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ double l=std::max(l1,l2);
|
|
|
+ double w=std::min(l1,l2);
|
|
|
+ if(l>2.100 && l<3.300 && w>1.400 && w<2.100)
|
|
|
+ {
|
|
|
+ //生成第四个点
|
|
|
+ cv::Point2f vec1=ps-pc;
|
|
|
+ cv::Point2f vec2=pt-pc;
|
|
|
+ cv::Point2f point4=(vec1+vec2)+pc;
|
|
|
+ points.push_back(point4);
|
|
|
+ std::cout << "3 wheels rectangle verify OK cos angle=" << cosa << " L=" << l
|
|
|
+ << " w=" << w;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ std::cout<< "3 wheels rectangle verify Failed cos angle=" << cosa << " L=" << l
|
|
|
+ << " w=" << w;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+bool Region_detector::clustering(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in) {
|
|
|
+ if (cloud_in->size() == 0) return false;
|
|
|
/////聚类
|
|
|
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
|
|
|
- kdtree->setInputCloud(cut_cloud);
|
|
|
+ kdtree->setInputCloud(cloud_in);
|
|
|
|
|
|
pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering;
|
|
|
// 设置聚类的最小值 2cm (small values may cause objects to be divided
|
|
@@ -79,38 +191,53 @@ bool Region_detector::clustering(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in){
|
|
|
clustering.setMinClusterSize(10);
|
|
|
clustering.setMaxClusterSize(500);
|
|
|
clustering.setSearchMethod(kdtree);
|
|
|
- clustering.setInputCloud(cut_cloud);
|
|
|
+ clustering.setInputCloud(cloud_in);
|
|
|
std::vector<pcl::PointIndices> clusters;
|
|
|
clustering.extract(clusters);
|
|
|
+ std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> seg_clouds;
|
|
|
+ for (int i = 0; i < clusters.size(); ++i) {
|
|
|
+ seg_clouds.push_back(pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>));
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < 4; ++i) {
|
|
|
- m_cloud_segs[i]->clear();
|
|
|
+ int j = 0;
|
|
|
+ for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it) {
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+ //创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
|
|
|
+ for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit) {
|
|
|
+ cloud_cluster->points.push_back(cloud_in->points[*pit]);
|
|
|
+ cloud_cluster->width = cloud_cluster->points.size();
|
|
|
+ cloud_cluster->height = 1;
|
|
|
+ cloud_cluster->is_dense = true;
|
|
|
+ }
|
|
|
+ seg_clouds[j] = cloud_cluster;
|
|
|
+ j++;
|
|
|
}
|
|
|
- if(clusters.size()==4)
|
|
|
+
|
|
|
+ std::cout << " cluster class:" << clusters.size() << std::endl;
|
|
|
+
|
|
|
+ std::vector<cv::Point2f> cvPoints;
|
|
|
+ for(int i=0;i<clusters.size();++i)
|
|
|
{
|
|
|
- int j = 0;
|
|
|
- for (std::vector<pcl::PointIndices>::const_iterator it = clusters.begin(); it != clusters.end(); ++it)
|
|
|
+ if(seg_clouds[i]->size()==0)
|
|
|
+ continue;
|
|
|
+ float sumX=0,sumY=0;
|
|
|
+ for(int j=0;j<seg_clouds[i]->size();++j)
|
|
|
{
|
|
|
- pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
- //创建新的点云数据集cloud_cluster,将所有当前聚类写入到点云数据集中
|
|
|
- for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit)
|
|
|
- {
|
|
|
- cloud_cluster->points.push_back(cut_cloud->points[*pit]);
|
|
|
- cloud_cluster->width = cloud_cluster->points.size();
|
|
|
- cloud_cluster->height = 1;
|
|
|
- cloud_cluster->is_dense = true;
|
|
|
- }
|
|
|
- m_cloud_segs[j]=cloud_cluster;
|
|
|
- j++;
|
|
|
+ sumX+=seg_clouds[i]->points[j].x;
|
|
|
+ sumY+=seg_clouds[i]->points[j].y;
|
|
|
}
|
|
|
- // std::cout<<" cluster class:"<<clusters.size()<<std::endl;
|
|
|
- return true;
|
|
|
+
|
|
|
+ float center_x=sumX/float(seg_clouds[i]->size());
|
|
|
+ float center_y=sumY/float(seg_clouds[i]->size());
|
|
|
+ cvPoints.push_back(cv::Point2f(center_x,center_y));
|
|
|
}
|
|
|
- return false;
|
|
|
+ return isRect(cvPoints);
|
|
|
+
|
|
|
}
|
|
|
|
|
|
bool Region_detector::detect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in)
|
|
|
{
|
|
|
+ return false;
|
|
|
bool result = false;
|
|
|
preprocess(cloud_in, cut_cloud);
|
|
|
|
|
@@ -134,29 +261,22 @@ bool Region_detector::detect(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in, doubl
|
|
|
|
|
|
m_seg_mutex.lock();
|
|
|
result = clustering(cloud_filterd);
|
|
|
- // std::cout<<"--------detector after clustering------"<<std::endl;
|
|
|
- if(result){
|
|
|
- // 获得四类,计算中心点角度等
|
|
|
- std::vector<Eigen::Vector4f> centers;
|
|
|
- std::vector<cv::Point2f> center_2d_points;
|
|
|
- Eigen::Vector4f car_center;
|
|
|
- for (size_t i = 0; i < 4; i++)
|
|
|
- {
|
|
|
- // 创建存储点云重心的对象
|
|
|
- Eigen::Vector4f centroid;
|
|
|
- if(0 == pcl::compute3DCentroid(*m_cloud_segs[i], centroid))
|
|
|
- return false;
|
|
|
- centers.push_back(centroid);
|
|
|
- car_center += centroid;
|
|
|
- center_2d_points.push_back(cv::Point2f(centroid[0], centroid[1]));
|
|
|
- }
|
|
|
- // std::cout<<"--------detector find center------"<<std::endl;
|
|
|
- car_center /= 4.0;
|
|
|
- x = car_center[0];
|
|
|
- y = car_center[1];
|
|
|
|
|
|
- cv::RotatedRect wheel_box = cv::minAreaRect(center_2d_points);
|
|
|
- // std::cout<<"--------detector find rect -----"<<std::endl;
|
|
|
+
|
|
|
+
|
|
|
+ if(result)
|
|
|
+ {
|
|
|
+ // convert all points after preprocessing into 2d
|
|
|
+ std::vector<cv::Point2f> all_points;
|
|
|
+ // car center
|
|
|
+ for (int j = 0; j < cloud_filterd->size(); ++j) {
|
|
|
+ all_points.push_back(cv::Point2f(cloud_filterd->points[j].x, cloud_filterd->points[j].y));
|
|
|
+ }
|
|
|
+ std::cout<<"--------detector find center------"<<std::endl;
|
|
|
+ cv::RotatedRect wheel_box = cv::minAreaRect(all_points);
|
|
|
+ x=wheel_box.center.x;
|
|
|
+ y=wheel_box.center.y;
|
|
|
+ std::cout<<"--------detector find rect -----"<<std::endl;
|
|
|
cv::Point2f vec;
|
|
|
cv::Point2f vertice[4];
|
|
|
wheel_box.points(vertice);
|