赞
踩
RANSAC 算法的输入是一组观测值、一个可以解释或拟合到观测值的参数化模型,以及一些置信度参数。
RANSAC 通过迭代选择原始数据的随机子集来实现其目标。这些数据是假设的入值,然后按如下方式测试此假设:
模型拟合到假设的入值,即模型的所有自由参数都是从进值重建的。
然后,根据拟合模型测试所有其他数据,如果某个点与估计的模型非常契合,则也将其视为假设的进一值。
如果有足够的点被归类为假设的入值,则估计的模型是相当好的。
该模型是从所有假设的入值中重新估计的,因为它仅从初始的假设入值集进行估计。
最后,通过估计值相对于模型的误差来评估模型。
此过程重复固定次数,每次生成因点太少而被丢弃的模型,或将优化模型与相应的误差度量一起进行。在后一种情况下,如果优化模型的误差低于上次保存的模型,我们将保留该模型。
ransac法选择对应点,对两组点云进行匹配
// RansacRegistration.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <time.h> #include <array> #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/registration/transformation_estimation_svd.h> #include <pcl/common/transforms.h> #include <pcl/kdtree/kdtree_flann.h> #include <pcl/visualization/pcl_visualizer.h> #include <iostream> #include <vector> using namespace std; using namespace pcl; //计算两点距离的平方 double PointDistance(PointXYZ P1, PointXYZ P2) { double ans = sqrt((P1.x - P2.x)*(P1.x - P2.x) + (P1.y - P2.y)*(P1.y - P2.y) + (P1.z - P2.z)*(P1.z - P2.z)); return ans; } //计算三点是否够远 bool ThreePointsDistanceCheck(PointXYZ P1, PointXYZ P2, PointXYZ P3, int nMinDis) { if (PointDistance(P1, P2) < nMinDis) return false; if (PointDistance(P1, P3) < nMinDis) return false; if (PointDistance(P3, P2) < nMinDis) return false; return true; } //点云可视化 void visualize_pcd(PointCloud<PointXYZ>::Ptr pcd_src, PointCloud<PointXYZ>::Ptr pcd_tgt, PointCloud<PointXYZ>::Ptr pcd_final) { //int vp_1, vp_2; // Create a PCLVisualizer object pcl::visualization::PCLVisualizer viewer("registration Viewer"); //viewer.createViewPort (0.0, 0, 0.5, 1.0, vp_1); // viewer.createViewPort (0.5, 0, 1.0, 1.0, vp_2); pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> src_h(pcd_src, 0, 255, 0); pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> tgt_h(pcd_tgt, 255, 0, 0); pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> final_h(pcd_final, 0, 0, 255); viewer.addPointCloud(pcd_src, src_h, "source cloud"); viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud"); viewer.addPointCloud(pcd_final, final_h, "final cloud"); //viewer.addCoordinateSystem(1.0); while (!viewer.wasStopped()) { viewer.spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); } } int main(int argc, char** argv) { PointCloud<PointXYZ>::Ptr cloud1(new PointCloud<PointXYZ>); io::loadPCDFile("e:\\FeatureCloud_sofa.pcd", *cloud1); visualize_pcd(cloud1,cloud1,cloud1); //读取点云 char* strTgtFile = new char[80]; char* strSrcFile = new char[80]; strcpy(strTgtFile, "e:\\data\\office2.pcd"); strcpy(strSrcFile, "e:\\data\\office1.pcd"); PointCloud<PointXYZ>::Ptr CloudTgt(new PointCloud<PointXYZ>); PointCloud<PointXYZ>::Ptr CloudSrc(new PointCloud<PointXYZ>); io::loadPCDFile(strTgtFile, *CloudTgt); io::loadPCDFile(strSrcFile, *CloudSrc); int nTgtPoint = CloudTgt->width;//查询点云文件内点的数量 int nSrcPoint = CloudSrc->width; int CorrsSrc[3] = { 0 }, CorrsTgt[3] = { 0 };//对应点对索引 double MinFitnessScore = 1000000.0; double MaxFitnessScore = 1.0; registration::TransformationEstimationSVD<PointXYZ, PointXYZ>::Matrix4 FinalTransformation; PointCloud<PointXYZ>::Ptr CloudSrcOutput(new PointCloud<PointXYZ>()); int nIter = 0, nTry = 0; srand((unsigned int)time(0)); for (nTry = 0; nIter < 2000; nTry++) { //cout << "---------------------------try:" << nTry << endl; //源点云随机选取三个符合距离要求的点s1,s2,s3 int nRand; do { for (int i = 0; i < 3; i++) { nRand = rand(); int p = nRand % (nSrcPoint)+1; CorrsSrc[i] = p; } } while (!ThreePointsDistanceCheck(CloudSrc->points[CorrsSrc[0]], CloudSrc->points[CorrsSrc[1]], CloudSrc->points[CorrsSrc[2]], 1000)); //cout << "choose from source:\nNo." << CorrsSrc[0] << ":(" << CloudSrc->points[CorrsSrc[0]].x << "," << CloudSrc->points[CorrsSrc[0]].y << "," << CloudSrc->points[CorrsSrc[0]].z << ").\n" // << "No." << CorrsSrc[1] << ":(" << CloudSrc->points[CorrsSrc[1]].x << "," << CloudSrc->points[CorrsSrc[1]].y << "," << CloudSrc->points[CorrsSrc[1]].z << ").\n" // << "No." << CorrsSrc[2] << ":(" << CloudSrc->points[CorrsSrc[2]].x << "," << CloudSrc->points[CorrsSrc[2]].y << "," << CloudSrc->points[CorrsSrc[2]].z << ").\n"; double dDisSrcP0P1 = PointDistance(CloudSrc->points[CorrsSrc[0]], CloudSrc->points[CorrsSrc[1]]); double dDisSrcP1P2 = PointDistance(CloudSrc->points[CorrsSrc[1]], CloudSrc->points[CorrsSrc[2]]); double dDisSrcP0P2 = PointDistance(CloudSrc->points[CorrsSrc[0]], CloudSrc->points[CorrsSrc[2]]); double dDisTgtP0P1 = 0, dDisTgtP1P2 = 0, dDisTgtP0P2 = 0; //在目标点云内随机选取一点t1 { nRand = rand(); int p = nRand % (nTgtPoint)+1; CorrsTgt[0] = p; } //cout << "choose from target:\nNo." << CorrsTgt[0] << ":(" << CloudTgt->points[CorrsTgt[0]].x << "," << CloudTgt->points[CorrsTgt[0]].y << "," << CloudTgt->points[CorrsTgt[0]].z << ").\n"; //在目标点云随机寻找第二点 int i = 0; vector<int> nTgtP1; for (i = 0; i < nTgtPoint; i++) { dDisTgtP0P1 = PointDistance(CloudTgt->points[i], CloudTgt->points[CorrsTgt[0]]); if (fabs(dDisTgtP0P1 - dDisSrcP0P1) < 1) nTgtP1.push_back(i); } if (nTgtP1.size() > 0) { nRand = rand(); int p = nRand % (nTgtP1.size()); CorrsTgt[1] = nTgtP1.at(p); } nTgtP1.clear(); //cout << "No." << CorrsTgt[1] << ":(" << CloudTgt->points[CorrsTgt[1]].x << ", " << CloudTgt->points[CorrsTgt[1]].y << ", " << CloudTgt->points[CorrsTgt[1]].z << ").\n"; //在目标点云寻找第三点 i = 0; vector<int> nTgtP2; for (i = 0; i < nTgtPoint; i++) { dDisTgtP0P2 = PointDistance(CloudTgt->points[CorrsTgt[0]], CloudTgt->points[i]); dDisTgtP1P2 = PointDistance(CloudTgt->points[CorrsTgt[1]], CloudTgt->points[i]); if ((fabs(dDisTgtP0P2 - dDisSrcP0P2) < 1) && (fabs(dDisTgtP1P2 - dDisSrcP1P2) < 1)) nTgtP2.push_back(i); } if (nTgtP2.size() > 0) { nRand = rand(); int p = nRand % (nTgtP2.size()); CorrsTgt[2] = nTgtP2.at(p); } nTgtP2.clear(); //cout << "No." << CorrsTgt[2] << ":(" << CloudTgt->points[CorrsTgt[2]].x << ", " << CloudTgt->points[CorrsTgt[2]].y << ", " << CloudTgt->points[CorrsTgt[2]].z << ").\n"; if (CorrsTgt[1] == nTgtPoint - 1 || CorrsTgt[2] == nTgtPoint - 1)//目标点云中搜寻到最后一点 continue; if (PointDistance(CloudTgt->points[CorrsTgt[0]], CloudSrc->points[CorrsSrc[0]]) > 500 || PointDistance(CloudTgt->points[CorrsTgt[1]], CloudSrc->points[CorrsSrc[1]]) > 500 || PointDistance(CloudTgt->points[CorrsTgt[2]], CloudSrc->points[CorrsSrc[2]]) > 500) continue;//对应点距离过大 if (CorrsTgt[0] == CorrsTgt[1] || CorrsTgt[0] == CorrsTgt[2] || CorrsTgt[1] == CorrsTgt[2]) continue; cout << "-----------------------------iteration:" << nIter++ << endl; //计算旋转矩阵 PointCloud<PointXYZ>::Ptr CloudPointSrc(new PointCloud<PointXYZ>()); PointCloud<PointXYZ>::Ptr CloudPointTgt(new PointCloud<PointXYZ>()); CloudPointSrc->width = 3; CloudPointSrc->height = 1; CloudPointSrc->is_dense = false; CloudPointSrc->resize(CloudPointSrc->width * CloudPointSrc->height); CloudPointTgt->width = 3; CloudPointTgt->height = 1; CloudPointTgt->is_dense = false; CloudPointTgt->resize(CloudPointTgt->width * CloudPointTgt->height); //同名点写入点云 CloudPointSrc->points[0] = CloudSrc->points[CorrsSrc[0]]; CloudPointSrc->points[1] = CloudSrc->points[CorrsSrc[1]]; CloudPointSrc->points[2] = CloudSrc->points[CorrsSrc[2]]; CloudPointTgt->points[0] = CloudTgt->points[CorrsTgt[0]]; CloudPointTgt->points[1] = CloudTgt->points[CorrsTgt[1]]; CloudPointTgt->points[2] = CloudTgt->points[CorrsTgt[2]]; //利用SVD方法求解变换矩阵 registration::TransformationEstimationSVD<PointXYZ, PointXYZ> TESVD; registration::TransformationEstimationSVD<PointXYZ, PointXYZ>::Matrix4 transformation; TESVD.estimateRigidTransformation(*CloudPointSrc, *CloudPointTgt, transformation); cout << "estimated rotation:" << endl; printf(" | %6.3f %6.3f %6.3f | \n", transformation(0, 0), transformation(0, 1), transformation(0, 2)); printf("R = | %6.3f %6.3f %6.3f | \n", transformation(1, 0), transformation(1, 1), transformation(1, 2)); printf(" | %6.3f %6.3f %6.3f | \n", transformation(2, 0), transformation(2, 1), transformation(2, 2)); printf("\n"); printf("t = < %0.3f, %0.3f, %0.3f >\n", transformation(0, 3), transformation(1, 3), transformation(2, 3)); //旋转源点云,计算匹配分数 double FitnessScore = 0.0; transformPointCloud(*CloudSrc, *CloudSrcOutput, transformation); KdTreeFLANN<PointXYZ> kdtree; kdtree.setInputCloud(CloudTgt); int K = 10; std::vector<int> nn_indices(K); std::vector<float> nn_dists(K); int nr = 0; for (i = 0; i < CloudSrcOutput->points.size(); i = i + 4) { // Find its nearest neighbor in the target kdtree.nearestKSearch(CloudSrcOutput->points[i], 1, nn_indices, nn_dists); // Deal with occlusions (incomplete targets)//部分被遮挡 if (nn_dists[0] <= 5000) { // Add to the fitness score FitnessScore += nn_dists[0]; nr++; } } if (nr > 0) FitnessScore = (FitnessScore / nr); else FitnessScore = std::numeric_limits<double>::max(); cout << "FitnessScore is:" << FitnessScore << endl; if (FitnessScore < MinFitnessScore) { MinFitnessScore = FitnessScore; FinalTransformation = transformation; } } //输出最终旋转矩阵 transformPointCloud(*CloudSrc, *CloudSrcOutput, FinalTransformation); FILE* pfOutputTransformation; char* strOutputTransformation = new char[80]; strcpy(strOutputTransformation, "e:\\Transformation.txt"); fopen_s(&pfOutputTransformation, strOutputTransformation, "w"); if (pfOutputTransformation == NULL) return 1; fprintf(pfOutputTransformation, "Min Fitness Score is:%f\n", MinFitnessScore); fprintf(pfOutputTransformation, "estimated rotation of \"%s\" and \"%s\" :\n", strTgtFile, strSrcFile); fprintf(pfOutputTransformation, " | %6.3f %6.3f %6.3f | \n", FinalTransformation(0, 0), FinalTransformation(0, 1), FinalTransformation(0, 2)); fprintf(pfOutputTransformation, "R = | %6.3f %6.3f %6.3f | \n", FinalTransformation(1, 0), FinalTransformation(1, 1), FinalTransformation(1, 2)); fprintf(pfOutputTransformation, " | %6.3f %6.3f %6.3f | \n", FinalTransformation(2, 0), FinalTransformation(2, 1), FinalTransformation(2, 2)); fprintf(pfOutputTransformation, "\n"); fprintf(pfOutputTransformation, "t = < %0.3f, %0.3f, %0.3f >\n", FinalTransformation(0, 3), FinalTransformation(1, 3), FinalTransformation(2, 3)); fclose(pfOutputTransformation); delete[] strOutputTransformation; strOutputTransformation = NULL; delete[] strTgtFile; strTgtFile = NULL; delete[] strSrcFile; strSrcFile = NULL; //输出旋转后源点云+目标点云 io::savePCDFileASCII("e:\\OutputCloud.pcd", *CloudSrcOutput); visualize_pcd(CloudSrc, CloudTgt, CloudSrcOutput); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。