使用RANSAC算法基于几何模型分割图像
来源:互联网 发布:俄罗斯运营商网络制式 编辑:程序博客网 时间:2024/05/22 05:04
RanSaC算法(随机采样一致)原本是用于数据处理的一种经典算法,其作用是在大量噪声情况下,提取物体中特定的成分。下图是对RanSaC算法效果的说明。图中有一些点显然是满足某条直线的,另外有一团点是纯噪声。目的是在大量噪声的情况下找到直线方程,此时噪声数据量是直线的3倍。
如果用最小二乘法是无法得到这样的效果的,直线大约会在图中直线偏上一点。关于随机采样一致性算法的原理,在wiki百科上讲的很清楚,甚至给出了伪代码和matlab,C代码。见网址https://en.wikipedia.org/wiki/RANSAC. 我想换一个不那么严肃或者说不那么学术的方式来解释这个算法。实际上这个算法就是从一堆数据里挑出自己最心仪的数据。所谓心仪当然是有个标准(目标的形式:满足直线方程?满足圆方程?以及能容忍的误差e)。平面中确定一条直线需要2点,确定一个圆则需要3点。随机采样算法,其实就和小女生找男朋友差不多。
- 从人群中随便找个男生,看看他条件怎么样,然后和他谈恋爱,(平面中随机找两个点,拟合一条直线,并计算在容忍误差e中有多少点满足这条直线)
- 第二天,再重新找个男生,看看他条件怎么样,和男朋友比比,如果更好就换新的(重新随机选两点,拟合直线,看看这条直线是不是能容忍更多的点,如果是则记此直线为结果)
- 第三天,重复第二天的行为(循环迭代)
- 终于到了某个年龄,和现在的男朋友结婚(迭代结束,记录当前结果)
显然,如果一个女生按照上面的方法找男朋友,最后一定会嫁一个好的(我们会得到心仪的分割结果)。只要这个模型在直观上存在,该算法就一定有机会把它找到。优点是噪声可以分布的任意广,噪声可以远大于模型信息。
这个算法有两个缺点,第一,必须先指定一个合适的容忍误差e。第二,必须指定迭代次数作为收敛条件。综合以上特性,本算法非常适合从杂乱点云中检测某些具有特殊外形的物体。
PCL中的使用:
平面方程参数估计
常用的平面方程是平面的法线式:ax+by+cz=d,其中a^2+b^2+c^2=1,d>0,(a,b,c)为平面法矢,d为原点至平面的距离,这四个参数可以确定一个平面。
//存放局内点索引 pcl::PointIndices::Ptr inliers (new pcl::PointIndices); //创建分割对象 pcl::SACSegmentation<pcl::PointXYZ> seg; //选择模型系数是否需要优化 seg.setOptimizeCoefficients (true); //设置模型类型 seg.setModelType (pcl::SACMODEL_PLANE); //设置模型估计方法 seg.setMethodType (pcl::SAC_RANSAC); //设置最大迭代次数 seg.setMaxIterations(10000); //距离阈值(离散点到模型表面距离) seg.setDistanceThreshold (0.01); //输入点云 seg.setInputCloud (cloud); //计算模型参数和得到符合此模型的局内点索引 seg.segment (*inliers, *coefficients); //输出平面模型的四个参数 std::cerr << "Model coefficients: " << coefficients->values[0] << " " << coefficients->values[1] << " " << coefficients->values[2] << " " << coefficients->values[3] << std::endl;
其他模型的估计只要改变ModelType就可以了,除了平面以外,PCL几乎支持所有的几何形状。作为点云分割的基础算法,RanSaC很强大且必收敛,可以作为机器人抓取,识别等后续任务的前处理。
下面我贴的代码是去除点云里大片的平面部分所用的,因为有个桌子,这样可以去掉桌子的表面,就可以提取桌子上面的东西了,不然桌子上的东西点云是连续的。
#include <pcl/ModelCoefficients.h>#include <pcl/point_types.h>#include <pcl/io/pcd_io.h>#include <pcl/filters/extract_indices.h>#include <pcl/filters/voxel_grid.h>#include <pcl/features/normal_3d.h>#include <pcl/kdtree/kdtree.h>#include <pcl/sample_consensus/method_types.h>#include <pcl/sample_consensus/model_types.h>#include <pcl/segmentation/sac_segmentation.h>#include <pcl/segmentation/extract_clusters.h>#include <pcl/visualization/cloud_viewer.h>#include <string>intmain(int argc, char** argv){// Read in the cloud datapcl::PCDReader reader;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>), cloud_f_1(new pcl::PointCloud<pcl::PointXYZ>), cloud_f(new pcl::PointCloud<pcl::PointXYZ>);reader.read("table_scene_lms400.pcd", *cloud);std::cout << "PointCloud before filtering has: " << cloud->points.size() << " data points." << std::endl; //*// Create the filtering object: downsample the dataset using a leaf size of 1cmpcl::VoxelGrid<pcl::PointXYZ> vg;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);vg.setInputCloud(cloud);vg.setLeafSize(0.01f, 0.01f, 0.01f);vg.filter(*cloud_filtered);std::cout << "PointCloud after filtering has: " << cloud_filtered->points.size() << " data points." << std::endl; //*pcl::copyPointCloud(*cloud_filtered, *cloud_f_1);// Create the segmentation object for the planar model and set all the parameterspcl::SACSegmentation<pcl::PointXYZ> seg;pcl::PointIndices::Ptr inliers(new pcl::PointIndices);pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane(new pcl::PointCloud<pcl::PointXYZ>());pcl::PCDWriter writer;seg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_PLANE);seg.setMethodType(pcl::SAC_RANSAC);seg.setMaxIterations(100);seg.setDistanceThreshold(0.02);int i = 0, nr_points = (int)cloud_filtered->points.size();while (cloud_filtered->points.size() > 0.1 * nr_points){// Segment the largest planar component from the remaining cloudseg.setInputCloud(cloud_filtered);seg.segment(*inliers, *coefficients);if (inliers->indices.size() == 0){std::cout << "Could not estimate a planar model for the given dataset." << std::endl;break;}// Extract the planar inliers from the input cloudpcl::ExtractIndices<pcl::PointXYZ> extract;extract.setInputCloud(cloud_filtered);extract.setIndices(inliers);extract.setNegative(false);// Write the planar inliers to diskextract.filter(*cloud_plane);std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size() << " data points." << std::endl;// Remove the planar inliers, extract the restextract.setNegative(true);extract.filter(*cloud_f);cloud_filtered = cloud_f;}boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));int v1(0);viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);viewer->setBackgroundColor(0, 0, 0, v1);viewer->addText("Radius: 0.01", 10, 10, "v1 text", v1);viewer->addPointCloud<pcl::PointXYZ>(cloud_f_1,"sample cloud1", v1);int v2(0);viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);viewer->setBackgroundColor(0.3, 0.3, 0.3, v2);viewer->addText("Radius: 0.1", 10, 10, "v2 text", v2);viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "sample cloud2", v2);viewer->initCameraParameters();while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}return (0);}
阅读全文
0 0
- 使用RANSAC算法基于几何模型分割图像
- ransac算法–基于几何关系的图像特征匹配点对提纯
- 鱼眼图像校正算法(基于几何模型)(2D)
- 《基于几何成像模型的鱼眼镜头图像校正算法和技术研究》实现
- 基于OpenCV的图像几何变换算法
- 图像拼接中的RANSAC算法
- 基于热映像的图像分割算法
- 图像分割 1.基于阈值的算法
- 基于颜色信息的图像分割算法
- 图像配准建立仿射变换模型并用RANSAC算法评估
- 基于几何成像模型的鱼眼镜头图像校正算法和技术研究的实现与改进
- 图像变换几何模型
- 使用分水岭算法对图像进行分割
- 基于OpenCV 图像分割
- 基于阈值图像分割
- 【图像算法】彩色图像分割专题八:基于MeanShift的彩色分割
- 医学图像处理之一:基于标记的分水岭分割算法
- 基于粒子群算法的图像阈值分割
- 初学者如何从零学习人工智能?看完你就懂了
- 移动端 ionic angularjs列表和单选以及多选框混合使用问题
- Android 自定义View之随机生成图片验证码
- 在使用第三方的SDk 的时候我们一般都会需要添jar和so
- 数据存储全方案,详解持久化技术
- 使用RANSAC算法基于几何模型分割图像
- C语言基础-二维数组13
- ARM Cortex-M3核LPC1768的μCOS-II的移植练习-1
- Java线程的生命周期以及sleep方法应用
- Div被鼠标划过时其背景色变色的第六种方式
- Linq语法
- Redis集群设置密码
- C# #region
- 模态和非模态对话框