RANSAC算法实现 + 直线拟合

2023-11-19

一、RANSAC算法

1.参考资料

[1]题目来源与解析:商汤科技SLAM算法岗的RANSAC编程题

[2]牛客网题目:[编程题]线性回归

[3]牛客网解答参考:商汤科技某算法岗的编程题有点过分了啊

[4]RANSAC算法原理:RANSAC翻译、经典RANSAC以及其相关的改进的算法小结

[5]参考代码(只进行两点的估计):RANSAC 直线拟合算法

[6]最小二乘拟合直线原理:最小二乘法直线拟合:Ax+By+C=0

[7]最小二乘拟合直线代码:Ax+By+C=0 直线一般式拟合 c++/python

[8]最小二乘原理推导:最小二乘法求回归直线方程的推导过程

 

2.题目要求

拟合二维平面中的带噪音直线, 
其中有不超过10%的样本点远离了直线,另外90%的样本点可能有高斯噪声的偏移
要求输出为 
ax+by+c=0的形式 
其中a > 0 且 a^2 + b^2 = 1

输入描述:
第一个数n表示有多少个样本点  之后n*2个数 每次是每个点的x 和y

输出描述:
输出a,b,c三个数,至多可以到6位有效数字

示例1
输入
5
3 4
6 8
9 12
15 20
10 -10

输出
-0.800000 0.600000 0.000000
说明
本题共有10个测试点,每个点会根据选手输出的参数计算非噪音数据点的拟合误差E,并根据E来对每个数据点进行评分0-10分
输入数据的范围在-10000

3.RANSAC算法伪代码(转自[4])

伪码形式的算法如下所示: 
输入: 
data —— 一组观测数据 
model —— 适应于数据的模型 
n —— 适用于模型的最少数据个数 
k —— 算法的迭代次数 
t —— 用于决定数据是否适应于模型的阀值 
d —— 判定模型是否适用于数据集的数据数目 
输出: 
best_model —— 跟数据最匹配的模型参数(如果没有找到好的模型,返回null) 
best_consensus_set —— 估计出模型的数据点 
best_error —— 跟数据相关的估计出的模型错误

iterations = 0
best_model = null
best_consensus_set = null
best_error = 无穷大
while ( iterations < k )
    maybe_inliers = 从数据集中随机选择n个点
    maybe_model = 适合于maybe_inliers的模型参数
    consensus_set = maybe_inliers

    for ( 每个数据集中不属于maybe_inliers的点 )
        if ( 如果点适合于maybe_model,且错误小于t )
            将点添加到consensus_set
    if ( consensus_set中的元素数目大于d )
        已经找到了好的模型,现在测试该模型到底有多好
        better_model = 适合于consensus_set中所有点的模型参数
        this_error = better_model究竟如何适合这些点的度量
        if ( this_error < best_error )
            我们发现了比以前好的模型,保存该模型直到更好的模型出现
            best_model =  better_model
            best_consensus_set = consensus_set
            best_error =  this_error
    增加迭代次数
返回 best_model, best_consensus_set, best_error

3.最小二乘求解直线

公共内容:

变量名 计算公式
mX \overline{x}=\frac{1}{n}\sum\limits_{i=1}^{n}x_i
mY \overline{y}=\frac{1}{n}\sum\limits_{i=1}^{n}y_i
sXX \sum\limits_{i=1}^{n}(x_i-\overline{x})^2
sXY \sum\limits_{i=1}^{n}(x_i-\overline{x})(y_i-\overline{y})
sYY \sum\limits_{i=1}^{n}(y_i-\overline{y})^2

解法1:

参考资料[6]

解法2:

拟合直线 :

y=a+bx

最小化点到直线的平方和:

f=\sum\limits_{i=1}^{n}(y-a-bx)^2

函数f对参数a求导,并令其为0

\frac{\partial{f}}{\partial{a}}=-2\sum\limits_{i=1}^{n}(y_i-a-bx_i)=0

求得

\hat{a}=\overline{y}-b\overline{x}

将上式带入f,对参数b求导,并令其为0,有

\frac{\partial{f}}{\partial{b}}=-2\sum\limits_{i=1}^{n}((x_i-\overline{x})(y_i-\overline{y})-b(x_i-\overline{x})^2))=0

b = \frac{\sum\limits_{i=1}^{n}(x_i-\overline{x})(y_i-\overline{y})}{\sum\limits_{i=1}^{n}(x_i-\overline{x})^2}

或者f对参数b求导后,将\hat{a}=\overline{y}-b\overline{x}带入方程有

\frac{\partial{f}}{\partial{b}}=-2(\sum\limits_{i=1}^{n}x_iy_i-b\sum\limits_{i=1}^{n}x_i^2-n\mathop{\overline{x}\mathop{\overline{y}}}+nb\overline{x}^2)=0

b=\frac{\sum\limits_{i=1}^{n}x_iy_i-n\mathop{\overline{x}\mathop{\overline{y}}}}{\sum\limits_{i=1}^{n}x_i^2-n\overline{x}^2}

本文采用第一种形式

注意,采用同样的参数

    int k = 50;                //最大迭代次数
    int n = 2;                //适用于模型的最少数据个数
    double t = 0.01;        //用于决定数据是否适应于模型的阀值
    int d = data_size*0.5;    //判定模型是否适用于数据集的数据数目

解法1的通过率为100%

解法2的通过率为77.78%

暂时不明白为什么……

解法3:

根据参考资料[6],转换为二次型求最小值问题

第一种方法使用特征值分解,选取最小特征值对应的特征向量

第二种方法在二次型中,使用sin\alpha,cos\alpha替换待求量,求解参数方程

后续有时间的话会补上程序


4.算法实现

可以通过自定义模型,将该代码移植到其他程序中

/*************************************************
Author:	Sayheyheyhey

Date:2019-7-4

Description:根据伪代码实现通用的RANSAC模板
	    自定义线性模型,实现两种方式的直线拟合
**************************************************/

#include <random>
#include <iostream>
#include <time.h>
#include <set>
#include <cassert>
#include <limits.h>

using namespace std;
//数据点类型
struct st_point{
	st_point(){};
	st_point(double X, double Y) :x(X), y(Y){};
	double x;
	double y;
};
/**
  * @brief 线性模型
  *
  * Ax+By+C = 0;
*/
class linearModel{
public:
	//待估计参数
	double A, B, C;
public:
	linearModel(){};
	~linearModel(){};
	
	//使用两个点对直线进行初始估计
	void Update(vector<st_point> &data, set<int> &maybe_inliers){
		assert(maybe_inliers.size() == 2);		//初始化的点不为2个,报错
		//根据索引读取数据
		vector<int> points(maybe_inliers.begin(), maybe_inliers.end());
		st_point pts1 = data[points[0]];
		st_point pts2 = data[points[1]];
		//根据两个点计算直线参数(得到其中一组解,可以任意比例缩放)
		double delta_x = pts2.x - pts1.x;
		double delta_y = pts2.y - pts1.y;
		A = delta_y;
		B = -delta_x;
		C = -delta_y*pts2.x + delta_x*pts2.y;
	}

	//返回点到直线的距离
	double computeError(st_point point){
		double numerator = abs(A*point.x + B*point.y + C);
		double denominator = sqrt(A*A + B*B);
		return numerator / denominator;
	}

	//根据一致点的集合对直线进行重新估计
	double Estimate(vector<st_point> &data, set<int> &consensus_set){
		assert(consensus_set.size() >= 2);
		//求均值 means
		double mX, mY;
		mX = mY = 0;
		for (auto &index : consensus_set){
			mX += data[index].x;
			mY += data[index].y;
		}
		mX /= consensus_set.size();
		mY /= consensus_set.size();
		
		//求二次项的和 sum
		double sXX, sYY, sXY;
		sXX = sYY = sXY = 0;
		for (auto &index : consensus_set){
			st_point point;
			point = data[index];
			sXX += (point.x - mX)*(point.x - mX);
			sYY += (point.y - mY)*(point.y - mY);
			sXY += (point.x - mX)*(point.y - mY);
		}
		/*
		//解法1:求y=kx+b的最小二乘估计,然后再转换成一般形式
		//参考 https://blog.csdn.net/hookie1990/article/details/91406309
		bool isVertical = sXY == 0 && sXX < sYY;
		bool isHorizontal = sXY == 0 && sXX > sYY;
		bool isIndeterminate = sXY == 0 && sXX == sYY;
		double k = NAN;
		double b = NAN;

		if (isVertical)
		{
			A = 1;
			B = 0;
			C = mX;
		}
		else if (isHorizontal)
		{
			A = 0;
			B = 1;
			C = mY;
		}
		else if (isIndeterminate)
		{
			A = NAN;
			B = NAN;
			C = NAN;
		}
		else
		{
			k = (sYY - sXX + sqrt((sYY - sXX) * (sYY - sXX) + 4.0 * sXY * sXY)) / (2.0 * sXY);	//斜率
			b = mY - k * mX;															//截距
			//正则化项,使得A^2+B^2 = 1;
			double normFactor = 1 / sqrt(1 + k*k);
			A = normFactor * k;
			B = -normFactor;
			C = normFactor*b;
		}
		//返回残差
		if (isIndeterminate){
			return NAN;
		}
		double error = A*A*sXX + 2 * A*B*sXY + B*B*sYY;
                error /= consensus_set.size();
                return error;
		*/
		//解法2:
                if(sXX == 0){
                    A = 1;    
                    B = 0;
                    C = -mX;
                }
                else{
                    A = sXY/sXX;
                    B = -1;
                    C = mY - A*mX;
                    //归一化令A^2+B^2 = 1;
                    double normFactor = sqrt(A*A+B*B);
                    A /= normFactor;
                    B /= normFactor;
                    C /= normFactor;
                }
		double error = A*A*sXX + 2 * A*B*sXY + B*B*sYY;
                error /= consensus_set.size();    //求平均误差
		return error;
		
	}
};


/**
* @brief 运行RANSAC算法
*
* @param[in]	data	一组观测数据
* @param[in]	n		适用于模型的最少数据个数
* @param[in]	k		算法的迭代次数
* @param[in]	t		用于决定数据是否适应于模型的阀值
* @param[in]	d		判定模型是否适用于数据集的数据数目 
* @param[in&out]	model	自定义的待估计模型,为该函数提供Update、computeError和Estimate三个成员函数
*							运行结束后,模型参数被设置为最佳的估计值
* @param[out]	best_consensus_set	输出一致点的索引值
* @param[out]	best_error	输出最小损失函数
*/
template<typename T, typename U>
int ransac(vector<T> &data, int n, int k, double t, int d,
			U &best_model,set<int> &best_consensus_set, double &best_error){
	//1.初始化
	int  iterations = 0;	//迭代次数
	U maybe_model;			//使用随机选点初始化求得的模型
	U better_model;			//根据符合条件的一致点拟合出的模型
	
	int isFound = 0;					//算法成功的标志
	set<int> maybe_inliers;				//初始随机选取的点(的索引值)

	//best_error = DBL_MAX;	//初始化为最大值
	best_error = 1.7976931348623158e+308;
	default_random_engine rng(time(NULL));					//随机数生成器
	uniform_int_distribution<int> dist(0, data.size()-1);	//采用均匀分布
	
	//2.主循环
	while (iterations < k){
		//3.随机选点
		maybe_inliers.clear();	
		while (1){
			int index = dist(rng);
			maybe_inliers.insert(index);
			if (maybe_inliers.size() == n){
				break;
			}
		}
		//4.计算初始值
		maybe_model.Update(data, maybe_inliers);								//自定义函数,更新模型
		set<int> consensus_set(maybe_inliers.begin(),maybe_inliers.end());		//选取模型后,根据误差阈值t选取的内点(的索引值)

		//5.根据初始模型和阈值t选择内点	
		for (int i = 0; i < data.size(); i++){
			double error_per_item = maybe_model.computeError(data[i]);
			if (error_per_item < t){
				consensus_set.insert(i);
			}
		}
		//6.根据全部的内点重新计算模型
		if (consensus_set.size() > d){
			double this_error = better_model.Estimate(data, consensus_set);		//自定义函数,(最小二乘)更新模型,返回计算出的误差
			//7.若当前模型更好,则更新输出量
			if (this_error < best_error){
				best_model = better_model;
				best_consensus_set = consensus_set;
				best_error = this_error;
			}
			isFound = 1;
		}
		++iterations;
	}
	return isFound;
}


int main(){
	//1.读入数据
	int data_size;		//输入第一行表示数据大小
	cin >> data_size;	
	vector<st_point> Points(data_size);
	for (int i = 0; i < data_size; i++){
		cin >> Points[i].x >> Points[i].y;
	}
	//测试用
	//vector<st_point> Points{ st_point(3, 4), st_point(6, 8), st_point(9, 12), st_point(15, 20), st_point(10,-10)};
	//int data_size = Points.size();
	//2.设置输入量
	int k = 50;				//最大迭代次数
	int n = 2;				//适用于模型的最少数据个数
	double t = 0.01;		//用于决定数据是否适应于模型的阀值
	int d = data_size*0.5;	//判定模型是否适用于数据集的数据数目 
	//3.初始化输出量
	linearModel best_model;			//最佳线性模型
	set<int> best_consensus_set;	//记录一致点索引的set
	double best_error;				//最小残差
	//4.运行RANSAC			
	int status = ransac(Points, n, k, t, d, best_model, best_consensus_set, best_error);
	//5.输出
	cout << best_model.A << " " << best_model.B << " " << best_model.C << endl;
	return 0;
}

运行结果:

k = 50, n=2, t=0.01, d = data_size*0.5时

解法1:

您的代码已保存
答案正确:恭喜!您提交的程序通过了所有的测试用例

解法2:

您的代码已保存
答案错误:您提交的程序没有通过所有的测试用例
case通过率为77.78%

简单解法:

可将Estimate的步骤注释掉进行实验,根据consensus_set计算this_error

您的代码已保存
答案正确:恭喜!您提交的程序通过了所有的测试用例

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RANSAC算法实现 + 直线拟合 的相关文章

  • 如何在MVVM中管理多个窗口

    我知道有几个与此类似的问题 但我还没有找到明确的答案 我正在尝试深入研究 MVVM 并尽可能保持纯粹 但不确定如何在坚持模式的同时启动 关闭窗口 我最初的想法是向 ViewModel 发送数据绑定命令 触发代码来启动一个新视图 然后通过 X
  • 如何检查图像对象与资源中的图像对象是否相同?

    所以我试图创建一个简单的程序 只需在单击图片框中更改图片即可 我目前只使用两张图片 所以我的图片框单击事件函数的代码 看起来像这样 private void pictureBox1 Click object sender EventArgs
  • C# 和 Javascript SHA256 哈希的代码示例

    我有一个在服务器端运行的 C 算法 它对 Base64 编码的字符串进行哈希处理 byte salt Convert FromBase64String serverSalt Step 1 SHA256Managed sha256 new S
  • 如何使用GDB修改内存内容?

    我知道我们可以使用几个命令来访问和读取内存 例如 print p x 但是如何更改任何特定位置的内存内容 在 GDB 中调试时 最简单的是设置程序变量 参见GDB 分配 http sourceware org gdb current onl
  • 从父类调用子类方法

    a doStuff 方法是否可以在不编辑 A 类的情况下打印 B did stuff 如果是这样 我该怎么做 class Program static void Main string args A a new A B b new B a
  • 未解决的包含:“cocos2d.h” - Cocos2dx

    当我在 Eclipse 中导入 cocos2dx android 项目时 我的头文件上收到此警告 Unresolved inclusion cocos2d h 为什么是这样 它实际上困扰着我 该项目可以正确编译并运行 但我希望这种情况消失
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • WPF 中的调度程序和异步等待

    我正在尝试学习 WPF C 中的异步编程 但我陷入了异步编程和使用调度程序的困境 它们是不同的还是在相同的场景中使用 我愿意简短地回答这个问题 以免含糊不清 因为我知道我混淆了 WPF 中的概念和函数 但还不足以在功能上正确使用它 我在这里
  • 获取没有非标准端口的原始 url (C#)

    第一个问题 环境 MVC C AppHarbor Problem 我正在调用 openid 提供商 并根据域生成绝对回调 url 在我的本地机器上 如果我点击的话 效果很好http localhost 12345 login Request
  • Cython 和类的构造函数

    我对 Cython 使用默认构造函数有疑问 我的 C 类 Node 如下 Node h class Node public Node std cerr lt lt calling no arg constructor lt lt std e
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • 如何衡量两个字符串之间的相似度? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 给定两个字符串text1 and text2 public SOMEUSABLERETURNTYPE Compare string t
  • for循环中计数器变量的范围是多少?

    我在 Visual Studio 2008 中收到以下错误 Error 1 A local variable named i cannot be declared in this scope because it would give a
  • 如何将单个 char 转换为 int [重复]

    这个问题在这里已经有答案了 我有一串数字 例如 123456789 我需要提取它们中的每一个以在计算中使用它们 我当然可以通过索引访问每个字符 但是如何将其转换为 int 我研究过 atoi 但它需要一个字符串作为参数 因此 我必须将每个字
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • 从库中捕获主线程 SynchronizationContext 或 Dispatcher

    我有一个 C 库 希望能够将工作发送 发布到 主 ui 线程 如果存在 该库可供以下人员使用 一个winforms应用程序 本机应用程序 带 UI 控制台应用程序 没有 UI 在库中 我想在初始化期间捕获一些东西 Synchronizati
  • 将 unsigned char * (uint8_t *) 转换为 const char *

    我有一个带有 uint8 t 参数的函数 uint8 t ihex decode uint8 t in size t len uint8 t out uint8 t i hn ln for i 0 i lt len i 2 hn in i
  • 为什么 C# Math.Ceiling 向下舍入?

    我今天过得很艰难 但有些事情不太对劲 在我的 C 代码中 我有这样的内容 Math Ceiling decimal this TotalRecordCount this PageSize Where int TotalRecordCount

随机推荐

  • 数据仓库系列 - 缓慢渐变维度 (Slowly Changing Dimension) 常见的三种类型及原型设计...

    开篇介绍 在从 OLTP 业务数据库向 DW 数据仓库抽取数据的过程中 特别是第一次导入之后的每一次增量抽取往往会遇到这样的问题 业务数据库中的一些数据发生了更改 到底要不要将这些变化也反映到数据仓库中 在数据仓库中 哪些数据应该随之变化
  • STM32 USB HID 自定义设备 bulk 传输

    ST 意法半导体公司 为STM32系列处理器编写了外设USB的库 并提供了很好的参考例程 本文就是参考ST提供的例程 在STM32F4 discovery板子上实现usb bulk传输 Host端是在linux平台上利用libusb库函数写
  • mysql 临时表权限_MySQL临时表浅析

    一 MySQL如何使用内部临时表 在某些情况下 服务器会在处理query的时候组建内部临时表 这种表有两种存在形式 1 位于内存中 使用的是MEMORY存储引擎 内存临时表 2 位于磁盘上 使用MyISAM存储引擎 硬盘临时表 服务器可能在
  • 再介绍一种低成本的负电源电路

    前面介绍了几种产生负电源的方法 几种常用的产生负电源的方法 今天再来介绍一种低成本的负电源电路 用分离元件搭建 配合程序控制 实现正电源转负电源 先看电路 图中Q1 D1 L2和C1构成最基本的Buck Boost电路 L1 C2为一级LC
  • myeclipse非正常关闭处理办法

    myeclipse正常或非正常关闭后 再次运行 不显示启动时的logo和读条 进入主页面后程序基本就卡死 无法正常运行 解决办法 方法一 修改工作空间在刚启动Myeclipse的时候会有一个选择工作空间的地方 换一个新的工作空间即可 若是原
  • Redis7之介绍(一)

    一 介绍 1 1 基本了解 Remote Dictionary Server 远程字典服务 是完全开源的 使用ANSIC语言编写遵守BSD协议 是一个高性能的Key Value数据库提供了丰富的数据结构 例如String Hash List
  • 面试题: v-if和v-show有什么区别?

    面试题 v if和v show有什么区别 1 v if能够控制是否生成vnode 也就间接控制了是否生成对应的dom 当v if为true时 会生成对应的vnode 并生成对应的dom元素 当其为false时 不会生成对应的vnode 自然
  • openwrt 缺少 libc.so.6 libm.so.6 libpthread.so.0

    在开发openwrt时 编译内核的时候 自己写的代码在openwrt 编译报错 提示缺少依赖库文件 Package Gateway Auto is missing dependencies for the following librari
  • flutter版本号对比

    版本号对比 Future
  • 筛选素数之欧拉筛法 python实现 附带证明

    返回类型 列表 说明 返回小于upperBound的所有素数 def ouLaShai upperBound filter False for i in range upperBound 1 primeNumbers for num in
  • Java学习心得10——多态

    多态 一种类型的变量可以掌管多种类型的对象 这就是多态 说人话 直观理解成多种形态 人类就是多态的 黄种人 白种人 黑种人都是属于人类 人类这一个类可以表示黄种人 白种人 黑种人这三个类 这不就是多态多种形态吗 回到编程 Animal 动物
  • 【华为OD机试真题 python】数字加减游戏【2022 Q4

    题目描述 数字加减游戏 小明在玩一个数字加减游戏 只使用加法或者减法 将一个数字s变成数字t 在每个回合中 小明可以用当前的数字加上或减去一个数字 现在有两种数字可以用来加减 分别为a b a b 其中b没有使用次数限制 请问小明最少可以用
  • 第四章 Flume专题-日志采集工具

    一 Flume专题之组件及架构介绍 1 Flume概述 1 1 Flume定义 Flume是一种分布式的 高可靠的和高可用的服务 用于有效地收集 聚合和移动大量日志数据框架 Flume是一个简单灵活的基于流数据的体系结构 1 2 Flume
  • Delphi ListView 的用法

    Delphi ListView 的用法 常用技巧 增加 i ListView1 Items Count with ListView1 do begin ListItem Items Add ListItem Caption IntToStr
  • Vite搭建react+ts项目

    创建一个react项目 首先需要打开终端 进行vite的引入 yarn create vite 使用react模板创建项目 yarn create vite react test template react cd react test y
  • Float与二进制之间的转化(Java实现)

    在线转化 http www binaryconvert com 2 3 import java text DecimalFormat 4 5 6 public class SinglePrecision 7 8 浮点到二进制 9 publi
  • 采用通信方式控制台达B2伺服驱动器运行在速度模式

    目录 前言 一 伺服驱动器恢复出厂设置 二 伺服驱动器设置为速度模式 三 关闭告警信息 四 通讯功能设置 五 采用通信功能控制伺服驱动器按速度模式运行 总结 前言 最近 使用台达B2伺服驱动器做项目 项目中用伺服电机的速度模式驱动一个螺杆按
  • Linux笔记--查看Linux系统自动Kill掉的进程

    目录 1 前言 2 查看系统日志 3 参考 1 前言 今天在服务器训练一个模型 程序无任何错误 但一段时间后挂在后台的进程莫名被Kill掉 原因在于服务器 linux 系统的运行内存不足 为了避免系统奔溃 系统主动 kill 内存占用最大的
  • Python项目创建(Pycharm程序)

    点击 新建项目 创建一个新的项目 这一步重点在Python解释器的选择 一个是新建虚拟环境 另一个是使用已有环境 使用此工具新建环境 Virtualenv 新建后在项目根目录下会出现 venv 的文件夹 相当于把Python解释器复制过去一
  • RANSAC算法实现 + 直线拟合

    一 RANSAC算法 1 参考资料 1 题目来源与解析 商汤科技SLAM算法岗的RANSAC编程题 2 牛客网题目 编程题 线性回归 3 牛客网解答参考 商汤科技某算法岗的编程题有点过分了啊 4 RANSAC算法原理 RANSAC翻译 经典