使用RANSAC拟合二维直线

二维直线的拟合

  • 1、OpenCV实现
  • 2、RANSAC二维直线拟合实现

1、OpenCV实现

使用OpenCV实现二维直线的拟合:

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
using namespace cv;
using namespace std;int main( )
{const char* filename = "1.bmp";Mat src_image = imread(filename,1);if( src_image.empty() ){cout << "Couldn't open image!" << filename;return 0;}int img_width = src_image.cols;int img_height = src_image.rows;Mat gray_image,bool_image;cvtColor(src_image,gray_image,CV_RGB2GRAY);threshold(gray_image,bool_image,0,255,CV_THRESH_OTSU);imshow("二值图", bool_image);//获取二维点集vector<Point> point_set;Point point_temp;for( int i = 0; i < img_height; ++i){for( int j = 0; j < img_width; ++j ){if (bool_image.at<unsigned char>(i,j) < 255){point_temp.x = j;point_temp.y = i;point_set.push_back(point_temp);	}}}//直线拟合 	//拟合结果为一个四元素的容器,比如Vec4f - (vx, vy, x0, y0)//其中(vx, vy) 是直线的方向向量//(x0, y0) 是直线上的一个点Vec4f fitline;//拟合方法采用最小二乘法fitLine(point_set,fitline,CV_DIST_L2,0,0.01,0.01);//求出直线上的两个点double k_line = fitline[1]/fitline[0];Point p1(0,k_line*(0 - fitline[2]) + fitline[3]);Point p2(img_width - 1,k_line*(img_width - 1 - fitline[2]) + fitline[3]);//显示拟合出的直线方程:y=k_line*(x-fitline[2])+fitline[3]char text_equation[1024];sprintf(text_equation,"y-%.2f=%.2f(x-%.2f)",fitline[3],k_line,fitline[2]);putText(src_image,text_equation,Point(30,50),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);//显示拟合出的直线line(src_image,p1,p2,Scalar(0,0,255),2); imshow("原图+拟合结果", src_image);waitKey();return 0;
}

使用这种方式,只能在数据基本正确时,才能得到较好的拟合结果,当数据中存在噪声数据时,使用RANSAC的方式进行拟合是较好的拟合方式。

2、RANSAC二维直线拟合实现

二维直线的一般方程为:Ax+By+C=0。在这里插入图片描述
若:已知直线上的两点P1(X1,Y1)和P2(X2,Y2), P1和P2两点不重合;
则:
在这里插入图片描述
该式子对所有的直线方程均满足。
C++实现主要函数:

//mTrajectoryParams.MaxModelFitIterations=2000
int FitLineRansac(std::vector<cv::Point>& points, cv::Vec3f& line)
{int PointsNum = 2;std::vector<std::vector<size_t>> mvSets = std::vector<std::vector<size_t>>(mTrajectoryParams.MaxModelFitIterations, std::vector<size_t>(PointsNum, 0));//点的对数const int N = points.size();//新建一个容器vAllIndices存储点云索引,并预分配空间std::vector<size_t> vAllIndices;vAllIndices.reserve(N);//在RANSAC的某次迭代中,还可以被抽取来作为数据样本的索引,所以这里起的名字叫做可用的索引std::vector<size_t> vAvailableIndices;//初始化所有特征点对的索引,索引值0到N-1for (int i = 0; i < N; i++)vAllIndices.push_back(i);//用于进行随机数据样本采样,设置随机数种子SeedRandOnce(0);//开始每一次的迭代 for (int it = 0; it < mTrajectoryParams.MaxModelFitIterations; it++){//迭代开始的时候,所有的点都是可用的vAvailableIndices = vAllIndices;//选择最小的数据样本集for (size_t j = 0; j < PointsNum; j++){// 随机产生一对点的id,范围从0到N-1int randi = RandomInt(0, vAvailableIndices.size() - 1);// idx表示哪一个索引对应的点对被选中int idx = vAvailableIndices[randi];//将本次迭代这个选中的第j个特征点对的索引添加到mvSets中mvSets[it][j] = idx;// 由于这对点在本次迭代中已经被使用了,所以我们为了避免再次抽到这个点,就在"点的可选列表"中,// 将这个点原来所在的位置用vector最后一个元素的信息覆盖,并且删除尾部的元素// 这样就相当于将这个点的信息从"点的可用列表"中直接删除了vAvailableIndices[randi] = vAvailableIndices.back();vAvailableIndices.pop_back();}//依次提取出6个点}//迭代mMaxIterations次,选取各自迭代时需要用到的最小数据集int BestMatch = 0;std::multiset<float> verror;for (int it = 0; it < mTrajectoryParams.MaxModelFitIterations; it++){std::vector<cv::Point> pts;//选择6个点对进行迭代for (size_t j = 0; j < PointsNum; j++){//从mvSets中获取当前次迭代的某个特征点对的索引信息int idx = mvSets[it][j];cv::Point pt = points[idx];pts.push_back(pt);}//Ax+By+C=0float A = pts[1].y - pts[0].y;float B = pts[0].x - pts[1].x;float C = pts[1].x*pts[0].y - pts[0].x*pts[1].y;int Match = 0;verror.clear();for (int i = 0; i < points.size(); i++){float error = (A * points[i].x + B * points[i].y + C) / sqrt(A * A + B * B);if (abs(error) < 1)Match++;verror.insert(error);}if (Match > BestMatch){BestMatch = Match;line = cv::Vec3f(A, B, C);}}return 1;
}

随机处理函数:

//随机处理
static bool m_already_seeded = false;
inline void SeedRand(int seed)
{srand(seed);
}
inline void SeedRandOnce(int seed)
{//if (!m_already_seeded)//{SeedRand(seed);m_already_seeded = true;//}
}
inline int RandomInt(int min, int max)
{int d = max - min + 1;return int(((double)rand() / ((double)RAND_MAX + 1.0)) * d) + min;
}

绘制直线的例子:

cv::Vec3f Line;
FitLineRansac(points, Line);
cv::Mat imdraw = im.clone();
cv::cvtColor(imdraw, imdraw, cv::COLOR_GRAY2BGR);
cv::Point pt0, pt1;
if (abs(Line[0] / Line[1]) < 0.067)
{pt0 = cv::Point(0, -Line[2] / Line[1]);pt1 = cv::Point(imdraw.cols - 1, -Line[2] / Line[1]);
}
else if (abs(Line[0] / Line[1]) > 15)
{pt0 = cv::Point(-Line[2] / Line[0], 0);pt1 = cv::Point(-Line[2] / Line[0], imdraw.rows - 1);
}
else
{pt0 = cv::Point(0, -Line[2] / Line[1]);pt1 = cv::Point(-Line[2] / Line[0], 0);
}
cv::line(imdraw, pt0, pt1, cv::Scalar(0, 255, 0), 1, 8);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/588440.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【面试HOT200】数组篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试coding部分的&#xff0c;整理期间苛求每个算法题目&#xff0c;平衡可读性与代码性能&#xff08;leetcode运行复杂度均打败80%以上&#xff09;。 &#x1f970;来源&#xff1a;材料主要源于…

MySQL高可用MHA

一、MHA概述 1.1 什么是 MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点故障的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在…

[Leetcode笔记] 动态规划相关

前言 写题目写到了一些和动态规划相关的内容&#xff0c;所以在这里记录一下 LCR 089 题解思路 总的来说&#xff0c;就是用一个数组去存储当前的最优解&#xff0c;然后从0开始一路向上顺推过去&#xff0c;求得最后一位的最优解。 class Solution { public:int rob(vect…

mysql语句学习

SQL Select语句完整的执行顺序&#xff1a; 1、from子句组装来自不同数据源的数据&#xff1b; &#xff08;先join在on&#xff09; 2、where子句基于指定的条件对记录行进行筛选&#xff1b; 3、group by子句将数据划分为多个分组&#xff1b; 4、使用聚集函数进行计算&a…

Ts递归查找多个根节点树结构某一条数据

// 递归查找树结构数据 function getIsNode(nodes: any, code: string) {let found false;function search(nodes: any) {nodes.forEach((node: any) > {if (node.code code) { //code相等&#xff0c;视为找到&#xff0c;将found设置为truefound true;}// 否则查找子节…

推荐一款强大的开源自动化测试神器

搞过自动化测试的小伙伴&#xff0c;相信都知道&#xff0c;在Web自动化测试中&#xff0c;有一款自动化测试神器工具: selenium。结合标准的WebDriver API来编写Python自动化脚本&#xff0c;可以实现解放双手&#xff0c;让脚本代替人工在Web浏览器上完成指定的操作。 虽然s…

【LAMMPS学习】七、加速性能(3)通用技巧

7. 加速性能 7.1.基准测试 7.2.测试性能 7.3.通用技巧 以下是提高模拟性能的通用技巧。它们中的大多数只适用于当前性能中的某些模型和某些瓶颈&#xff0c;因此让您生成的计时数据作为指导。要预测这些选项会产生多大的差异&#xff0c;即使不是不可能&#xff0c;也是很难…

谷歌推出多模态视频模型,自动生成丰富动作视频

谷歌的研究人员推出了一款多模态扩散模型——VLOGGER。 用户只需要向VLOGGER输入图像、语音&#xff0c;就能生成带语音、丰富动作的人物视频。VLOGGER基于扩散模型开发而成&#xff0c;并提出了一种全新的架构&#xff0c;将文本生成图像模型与空间、时间控制相结合&#xff…

LangChain-04 RAG Retrieval-Augmented Generation 检索增强生成

内容简介 LangChain 中的 “RAG” 指的是 “Retrieval-Augmented Generation”&#xff0c;即检索增强生成。它是一种结合了检索&#xff08;从大量数据中检索相关信息&#xff09;和生成&#xff08;基于检索到的信息生成文本&#xff09;的技术&#xff0c;旨在改善和增强自…

TiDB单机版安装和连接访问

TiDB单机版安装和连接访问 1、下载 $wget http://download.pingcap.org/tidb-latest-linux-amd64.tar.gz 2、解压缩 $tar -zxvf tidb-latest-linux-amd64.tar.gz 3、启动TiDB 启动PD $./bin/pd-server --data-dirpd --log-filepd.log 启动tikv $./bin/tikv-server --pd…

MySQL 进阶-----索引使用规则

目录 前言 一、验证索引效率 二、最左前缀法则 三、范围查询 四、索引失效情况 1.索引列运算 2.字符串不加引号 3 .模糊查询 4.or连接条件 5 .数据分布影响 前言 本期我们学习MySQL索引的使用方法&#xff0c;在讲解索引的使用原则之前&#xff0c;先通过一个简单的…

Celery的任务流

Celery的任务流 在之前调用任务的时候只是使用delay()和apply_async()方法。但是有时我们并不想简单的执行单个异步任务&#xff0c;比如说需要将某个异步任务的结果作为另一个异步任务的参数或者需要将多个异步任务并行执行&#xff0c;返回一组返回值&#xff0c;为了实现此…