自适应阈值的ransac平面拟合
来源:互联网 发布:用友u8数据备份 编辑:程序博客网 时间:2024/06/06 00:16
原来一直用pcl中的ransac平面拟合,现在突然想自己写一个不需要设置阈值的ransac平面拟合,下面把我的代码贴出来,欢迎大神们指正。
#pragma once#include "new3s_PointXYZ.h"#include <vector>class RansacPlaneFit{public: RansacPlaneFit(); ~RansacPlaneFit(); void setInputCloud(const std::vector<new3s_PointXYZ> &clouds); // 设置距离阈值 void setThreshValue(const double threshvalue); // 设置最大迭代次数 void setIteration(const int iters); // 计算平面系数 Eigen::Matrix<double, 4, 1> computePlaneCoef(); bool getSample(std::vector<int> &samples); // 三点不共线为条件判断选择点是否可行 bool isGoodSample(const std::vector<int> &indices); // 计算点到直线的距离 double computeDist(const int index, const Eigen::Matrix4Xd &coefs); // 计算平面的系数 bool computeModelCoefficients(const std::vector<int> &samples, Eigen::Matrix<double , 4 , 1> &model_coefficient); // 统计在阈值范围内到平面的点数,并记录索引 int countNum(const Eigen::Matrix4Xd &model_coef , std::vector<int> &indices); // 计算点云中心 void compute3DCentroid(const std::vector<int> &indices , Eigen::Matrix<double, 4, 1> ¢roid); // 计算协方差矩阵 void computeCovarianceMatrix(const std::vector<int> &indices, const Eigen::Matrix<double, 4, 1> ¢roid, Eigen::Matrix<double, 3, 3> &covariance_matrix); // 设置inlier和outlier的比率 void setRatio(const double ratio); // 获得迭代次数 int getIteration() const; // 获得距离阈值 double getThreshValue() const;private: bool isSetThreshValue() const;private: // 点数 int m_num; std::vector<new3s_PointXYZ> m_cloud; double m_threshValue; // 设置迭代次数 int m_iters; // 记录程序迭代的次数 int m_iteration; // 保存采样索引 std::vector<int> m_samples; // 全局索引 std::vector<int> m_globalindexs; // inlier和outlier比率 double m_ratio; // 是否设置阈值标记 bool m_threshFlag;};
实现文件
#include "RansacPlaneFit.h"#include <Eigen/eigen3/Eigen/Eigen>#include <math.h>#include <iostream>RansacPlaneFit::RansacPlaneFit() : m_threshValue(0.0) , m_iters(1000) , m_num(0) , m_ratio(2.0) , m_threshFlag(false) , m_iteration(0){}RansacPlaneFit::~RansacPlaneFit(){ if (!m_cloud.empty()) { m_cloud.clear(); std::vector<new3s_PointXYZ>().swap(m_cloud); }}void RansacPlaneFit::setInputCloud(const std::vector<new3s_PointXYZ>& clouds){ if (!clouds.empty()) { m_cloud = clouds; m_num= m_cloud.size(); for (int i = 0 ; i < m_num; ++i) { m_globalindexs.push_back(i); } }}void RansacPlaneFit::setThreshValue(const double threshvalue){ m_threshValue = threshvalue; m_threshFlag = true;}void RansacPlaneFit::setIteration(const int iters){ m_iters = iters;}bool RansacPlaneFit::getSample(std::vector<int>& samples){ samples.resize(3); srand(unsigned(time(0))); int id1 = rand() % m_globalindexs.size(); int id2 = rand() % m_globalindexs.size(); int id3 = rand() % m_globalindexs.size(); samples[0] = id1; samples[1] = id2; samples[2] = id3; if (isGoodSample(samples)) { return true; } return false;}Eigen::Matrix<double, 4, 1> RansacPlaneFit::computePlaneCoef(){ Eigen::Matrix<double , 4 , 1> coef ; coef.setZero(); // 记录迭代次数 int iter = 0; // 记录内点数 int max_best_num = 0; std::vector<int> samples; // 统计每次迭代到拟合平面点的数量 std::vector<int> best_nums; std::vector<std::vector<int> > inlier_indices; inlier_indices.resize(m_iters); double ratio = 0; while (iter < m_iters) { ++iter; if (getSample(samples)) { computeModelCoefficients(samples, coef); ratio = (countNum(coef, inlier_indices[iter - 1]) / (double)(m_num - inlier_indices[iter - 1].size())); std::cout << "inlier和outlier的比率:" << ratio << std::endl; if (ratio > m_ratio) { break; } } samples.clear(); std::vector<int>().swap(samples); } m_iteration = iter;// std::sort(inlier_indices.begin(), inlier_indices.end()); best_nums.resize(inlier_indices[iter - 1].size()); std::copy(inlier_indices[iter - 1].begin(), inlier_indices[iter - 1].end(), best_nums.begin()); Eigen::Matrix<double, 4, 1> xyz_centroid; xyz_centroid.setZero(); compute3DCentroid(best_nums , xyz_centroid); Eigen::Matrix3d covariance_matrix; covariance_matrix.setZero(); computeCovarianceMatrix(best_nums, xyz_centroid, covariance_matrix); EIGEN_ALIGN16 Eigen::Vector3f::Scalar eigen_value; EIGEN_ALIGN16 Eigen::Vector3f eigen_vector; //计算协方差矩阵最小特征值的特征向量 Eigen::EigenSolver<Eigen::Matrix3d> CovarianceMatrix(covariance_matrix); Eigen::Matrix3d D = CovarianceMatrix.pseudoEigenvalueMatrix(); Eigen::Matrix3d V = CovarianceMatrix.pseudoEigenvectors(); std::vector<double> eval;//保存特征值 for (int i = 0; i < 3; ++i) { eval.push_back(D(i, i)); } int k_val = 0;//记录特征值最小的是哪个 double min_val = 100000000; for (int i = 0; i < 3; ++i) { if (eval[i] < min_val) { min_val = eval[i]; k_val = i; } } for (int i = 0; i < 3; ++i) { eigen_vector[i] = V(i, k_val); } coef[0] = eigen_vector[0]; coef[1] = eigen_vector[1]; coef[2] = eigen_vector[2]; coef[3] = 0; coef[3] = -1 * coef.dot(xyz_centroid); if (coef[3] != 0) { coef[0] /= coef[3]; coef[1] /= coef[3]; coef[2] /= coef[3]; coef[3] = 1.0; } return coef;}bool RansacPlaneFit::isGoodSample(const std::vector<int>& indices){ if (indices.size() < 3) { return false; } Eigen::Vector3d p0p1 = Eigen::Vector3d(m_cloud[indices[1]].get_x() - m_cloud[indices[0]].get_x(), m_cloud[indices[1]].get_y() - m_cloud[indices[0]].get_y(), m_cloud[indices[1]].get_z() - m_cloud[indices[0]].get_z()); Eigen::Vector3d p0p2 = Eigen::Vector3d(m_cloud[indices[2]].get_x() - m_cloud[indices[0]].get_x(), m_cloud[indices[2]].get_y() - m_cloud[indices[2]].get_y(), m_cloud[indices[1]].get_z() - m_cloud[indices[0]].get_z()); if (p0p1(0) * p0p2(1) == p0p2(0) * p0p1(1) && p0p1(1) * p0p2(2) == p0p2(1) * p0p1(2)) { return false; } return true;}double RansacPlaneFit::computeDist(const int index, const Eigen::Matrix4Xd & coefs){ double a = coefs(0, 0); double b = coefs(1, 0); double c = coefs(2, 0); double d = coefs(3, 0); double x = m_cloud[index].get_x(); double y = m_cloud[index].get_y(); double z = m_cloud[index].get_z(); return fabs((x * a + y * b + z * c + d) / (a * a + b * b + c * c));}bool RansacPlaneFit::computeModelCoefficients(const std::vector<int>& samples, Eigen::Matrix<double, 4, 1>& model_coefficient){ if (samples.size() != 3) { std::cout << "采样点数量不足3!\n"; return (false); } new3s_PointXYZ p0 = m_cloud[samples[0]]; new3s_PointXYZ p1 = m_cloud[samples[1]]; new3s_PointXYZ p2 = m_cloud[samples[2]]; Eigen::Vector3d p0p1(p1.get_x() - p0.get_x(), p1.get_y() - p0.get_y(), p1.get_z() - p0.get_z()); Eigen::Vector3d p0p2(p2.get_x() - p0.get_x(), p2.get_y() - p0.get_y(), p2.get_z() - p0.get_z()); // 利用向量的叉积求法向量 model_coefficient.resize(4); model_coefficient[0] = p0p1[1] * p0p2[2] - p0p2[1] * p0p1[2]; model_coefficient[1] = p0p2[0] * p0p1[2] - p0p1[0] * p0p2[2]; model_coefficient[2] = p0p1[0] * p0p2[1] - p0p2[0] * p0p1[1]; model_coefficient[3] = 0; model_coefficient.normalize(); //模型系数单位化 // ... + d = 0 model_coefficient[3] = -(model_coefficient[0] * p0.get_x() + model_coefficient[1] * p0.get_y() + model_coefficient[2] * p0.get_z()); return (true);}int RansacPlaneFit::countNum(const Eigen::Matrix4Xd &model_coef, std::vector<int> &indices){ double d = 0; if (isSetThreshValue() != true) //如果没有设置阈值,自适应产生距离阈值 { double adatp_threshVal = 0; std::vector<double> vec_d; double aved = 0; for (unsigned int i = 0; i < m_num; ++i) { d = computeDist(m_globalindexs[i], model_coef); aved += d; vec_d.push_back(d); } aved /= m_num; for (size_t i = 0; i < m_num; ++i) { adatp_threshVal += (vec_d[i] - aved) * (vec_d[i] - aved); } adatp_threshVal /= m_num; adatp_threshVal = std::sqrt(adatp_threshVal); m_threshValue = adatp_threshVal; } for (size_t i = 0; i < m_num; ++i) { d = computeDist(m_globalindexs[i], model_coef); if (d < m_threshValue) { indices.push_back(i); } } return indices.size();}void RansacPlaneFit::compute3DCentroid(const std::vector<int>& indices, Eigen::Matrix<double, 4, 1>& centroid){ if (indices.empty()) { std::cout << "索引文件为空!\n"; return; } centroid.setZero(); int num = indices.size(); for (int i = 0 ; i < num ; ++i) { centroid[0] += m_cloud[indices[i]].get_x(); centroid[1] += m_cloud[indices[i]].get_y(); centroid[2] += m_cloud[indices[i]].get_z(); } centroid /= static_cast<double>(indices.size()); centroid[3] = 1;}void RansacPlaneFit::computeCovarianceMatrix(const std::vector<int>& indices, const Eigen::Matrix<double, 4, 1>& centroid, Eigen::Matrix<double, 3, 3>& covariance_matrix){ if (indices.empty()) { std::cout << "索引为空!\n"; return ; } covariance_matrix.setZero(); size_t num = indices.size(); for (size_t i = 0; i < num; i++) { Eigen::Matrix<double, 4, 1> pt; pt[0] = m_cloud[indices[i]].get_x() - centroid[0]; pt[1] = m_cloud[indices[i]].get_y() - centroid[1]; pt[2] = m_cloud[indices[i]].get_z() - centroid[2]; covariance_matrix(1, 1) += pt.y() * pt.y(); covariance_matrix(1, 2) += pt.y() * pt.z(); covariance_matrix(2, 2) += pt.z() * pt.z(); pt *= pt.x(); covariance_matrix(0, 0) += pt.x(); covariance_matrix(0, 1) += pt.y(); covariance_matrix(0, 2) += pt.z(); } covariance_matrix(1, 0) = covariance_matrix(0, 1); covariance_matrix(2, 0) = covariance_matrix(0, 2); covariance_matrix(2, 1) = covariance_matrix(1, 2);}void RansacPlaneFit::setRatio(const double ratio){ m_ratio = ratio;}int RansacPlaneFit::getIteration() const{ return m_iteration;}double RansacPlaneFit::getThreshValue() const{ return m_threshValue;}bool RansacPlaneFit::isSetThreshValue() const{ return m_threshFlag;}main文件代码如下:#include <pcl/sample_consensus/ransac.h>#include <pcl/sample_consensus/sac_model_plane.h>#include <pcl/io/pcd_io.h>#include <pcl/point_types.h>#include <pcl/point_cloud.h>#include <math.h>#include <vector>#include "new3s_PointXYZ.h"#include <pcl/common/common.h>#include <pcl/common/centroid.h>#include <opencv.hpp>#include "RansacPlaneFit.h"d test_pcl(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, const std::vector<int> &indices);void test_opencv(cv::Mat &mat);void test_myself(const std::vector<new3s_PointXYZ> &clouds, const std::vector<int> &indices);void main(){ std::vector<new3s_PointXYZ> myself_cloud; pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); cloud->width = 10000; cloud->height = 1; cloud->is_dense = FALSE; cloud->resize(cloud->width * cloud->height); // 生成平面x2 + y2 + z2 = 1的点云数据 size_t num = cloud->size(); for (size_t i = 0 ; i < num ; ++i) { double x = rand() / (RAND_MAX + 1.0); double y = rand() / (RAND_MAX + 1.0); double z = 1 - (x + y); double z_outlier = rand() / (RAND_MAX + 1.0); cloud->points[i].x = x; cloud->points[i].y = y; // 生成局外点 if (i % 5 == 0) { cloud->points[i].z = z_outlier ; myself_cloud.push_back(new3s_PointXYZ(x , y , z_outlier)); } else { cloud->points[i].z = 1 - (cloud->points[i].x + cloud->points[i].y); myself_cloud.push_back(new3s_PointXYZ(x, y , z)); } }// pcl::io::savePCDFile("1.pcd", *cloud); // 保存局内点索引 std::vector<int> inliers; // 采样一致性模型对象 pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr model_p(new pcl::SampleConsensusModelPlane<pcl::PointXYZ>(cloud)); pcl::RandomSampleConsensus<pcl::PointXYZ> ransac(model_p); ransac.setDistanceThreshold(0.01); ransac.computeModel(); ransac.getInliers(inliers); std::cout << "局内点:" << inliers.size() << std::endl; pcl::PointCloud<pcl::PointXYZ>::Ptr final(new pcl::PointCloud<pcl::PointXYZ>); final->resize(inliers.size()); pcl::copyPointCloud(*cloud, inliers, *final); Eigen::VectorXf coef = Eigen::VectorXf::Zero(4 , 1); ransac.getModelCoefficients(coef); std::cout << "拟合系数:\n"; std::cout << "a = " << coef[0] << " b = " << coef[1] << " c = " <<coef[2]<< " d = " << coef[3] << "\n"; RansacPlaneFit ransacfit; ransacfit.setInputCloud(myself_cloud); Eigen::Matrix<double, 4, 1> myself_coef = ransacfit.computePlaneCoef(); std::cout << "迭代次数:" << ransacfit.getIteration() << std::endl; std::cout << "自适应距离阈值:" << ransacfit.getThreshValue() << std::endl; std::cout << "myself 拟合系数:" << std::endl; std::cout << myself_coef << std::endl;}
和pcl中的平面拟合做了一个比较,如果没有设定阈值,程序将自动计算出一个距离阈值。
阅读全文
0 0
- 自适应阈值的ransac平面拟合
- ransac平面拟合
- 利用 ransac 算法拟合平面
- [Matlab]基于matlab的ransac平面拟合程序
- matlab中实现RANSAC平面拟合
- RANSAC介绍(Matlab版直线拟合+平面拟合)
- 三维曲面总结:平面拟合、RANSAC、ICP算法
- 自适应的阈值化
- 平面拟合
- 最小二乘拟合&基于RANSAC的直线拟合&椭圆拟合
- Ransac算法--直线拟合
- Ransac算法--直线拟合
- 自适应阈值
- 自适应阈值
- 基于最小二乘法的平面拟合,背景去除
- RANSAC直线拟合和最小二乘直线拟合的简单介绍
- 图像分割自适应阈值的求取
- 带有 mask 的 OTSU 自适应阈值
- 二元查找树
- [JZOJ5165] 小W的动漫
- 湖南省第八届大学生计算机程序设计竞赛CSU--最短的名字
- TCP网络通信/线程池
- 【转载】SAP ABAP中自定义权限对象(AUTHORITY-CHECK)
- 自适应阈值的ransac平面拟合
- 外网远程桌面连接内网服务器教程(超详细)
- 浅谈C/C++中的typedef和#define
- 【转载】BAPI_GOODSMVT_CREATE FUNCITON FOR MIGO 各种移动类型 源代码参考
- python解析页面DOM树形成xpath列表,并计算DOM树的最大深度
- ==与equals()方法
- VMware虚拟机中如何配置静态IP
- android studio ndk编程(二)——两种方式编译
- 关于list集合传到jsp,在struts的select标签中显示下拉列表问题