Modified Least Square Method and Ransan Method to Fit Circle from Data
In OpenCv, it only provide the function fitEllipse to fit Ellipse, but doesn't provide function to fit circle, so i read some paper, and write a function to do it. The paper it refer to is "A Few Methods for Fitting Circles to Data".
Also when there is a lot of noise in the data, need to find a way to exclude the noise data and get a more accuracy result.
There are two methods, one is iterate method, first use all the data to fit a model, then find the points exceed the error tolerance to the model, excude them and fit again. Until reach iteration times limit or all the data is in error tolerance.
Another method is ransac method, it has detailed introduction in paper "Random Sample Consensus: A Paradigm for Model Fitting with Apphcatlons to Image Analysis and Automated Cartography".
// This function is based on Modified Least Square Methods from Paper
// "A Few Methods for Fitting Circles to Data".
cv::RotatedRect FitCircle(const std::vector<cv::Point2f> &vecPoints)
{
cv::RotatedRect rotatedRect;
if ( vecPoints.size() < )
return rotatedRect; double Sx = ., Sy = ., Sx2 = ., Sy2 = ., Sxy = ., Sx3 = ., Sy3 = ., Sxy2 = ., Syx2 = .;
for ( const auto &point : vecPoints ) {
Sx += point.x;
Sy += point.y;
Sx2 += point.x * point.x;
Sy2 += point.y * point.y;
Sxy += point.x * point.y;
Sx3 += point.x * point.x * point.x;
Sy3 += point.y * point.y * point.y;
Sxy2 += point.x * point.y * point.y;
Syx2 += point.y * point.x * point.x;
} double A, B, C, D, E;
int n = vecPoints.size();
A = n * Sx2 - Sx * Sx;
B = n * Sxy - Sx * Sy;
C = n * Sy2 - Sy * Sy;
D = 0.5 * ( n * Sxy2 - Sx * Sy2 + n * Sx3 - Sx * Sx2 );
E = 0.5 * ( n * Syx2 - Sy * Sx2 + n * Sy3 - Sy * Sy2 ); auto AC_B2 = ( A * C - B * B); // The variable name is from AC - B^2
auto am = ( D * C - B * E ) / AC_B2;
auto bm = ( A * E - B * D ) / AC_B2; double rSqureSum = .f;
for ( const auto &point : vecPoints )
{
rSqureSum += sqrt ( ( point.x - am ) * ( point.x - am ) + ( point.y - bm) * ( point.y - bm) );
}
float r = static_cast<float>( rSqureSum / n );
rotatedRect.center.x = static_cast<float>( am );
rotatedRect.center.y = static_cast<float>( bm );
rotatedRect.size = cv::Size2f( .f * r, .f * r ); return rotatedRect;
} std::vector<size_t> findPointOverTol( const std::vector<cv::Point2f> &vecPoints, const cv::RotatedRect &rotatedRect, int method, float tolerance )
{
std::vector<size_t> vecResult;
for ( size_t i = ;i < vecPoints.size(); ++ i ) {
cv::Point2f point = vecPoints[i];
auto disToCtr = sqrt( ( point.x - rotatedRect.center.x) * (point.x - rotatedRect.center.x) + ( point.y - rotatedRect.center.y) * ( point.y - rotatedRect.center.y ) );
auto err = disToCtr - rotatedRect.size.width / ;
if ( method == && fabs ( err ) > tolerance ) {
vecResult.push_back(i);
}else if ( method == && err > tolerance ) {
vecResult.push_back(i);
}else if ( method == && err < -tolerance ) {
vecResult.push_back(i);
}
}
return vecResult;
} //method 1 : Exclude all the points out of positive error tolerance and inside the negative error tolerance.
//method 2 : Exclude all the points out of positive error tolerance.
//method 3 : Exclude all the points inside the negative error tolerance.
cv::RotatedRect FitCircleIterate(const std::vector<cv::Point2f> &vecPoints, int method, float tolerance)
{
cv::RotatedRect rotatedRect;
if (vecPoints.size() < )
return rotatedRect; std::vector<cv::Point2f> vecLocalPoints;
for ( const auto &point : vecPoints ) {
vecLocalPoints.push_back ( point );
}
rotatedRect = FitCircle ( vecLocalPoints ); std::vector<size_t> overTolPoints = findPointOverTol ( vecLocalPoints, rotatedRect, method, tolerance );
int nIteratorNum = ;
while ( ! overTolPoints.empty() && nIteratorNum < ) {
for (auto it = overTolPoints.rbegin(); it != overTolPoints.rend(); ++ it)
vecLocalPoints.erase(vecLocalPoints.begin() + *it);
rotatedRect = FitCircle ( vecLocalPoints );
overTolPoints = findPointOverTol ( vecLocalPoints, rotatedRect, method, tolerance );
++ nIteratorNum;
}
return rotatedRect;
} std::vector<cv::Point2f> randomSelectPoints(const std::vector<cv::Point2f> &vecPoints, int needToSelect)
{
std::set<int> setResult;
std::vector<cv::Point2f> vecResultPoints; if ( (int)vecPoints.size() < needToSelect )
return vecResultPoints; while ((int)setResult.size() < needToSelect) {
int nValue = std::rand() % vecPoints.size();
setResult.insert(nValue);
}
for ( auto index : setResult )
vecResultPoints.push_back ( vecPoints[index] );
return vecResultPoints;
} std::vector<cv::Point2f> findPointsInTol( const std::vector<cv::Point2f> &vecPoints, const cv::RotatedRect &rotatedRect, float tolerance )
{
std::vector<cv::Point2f> vecResult;
for ( const auto &point : vecPoints ) {
auto disToCtr = sqrt( ( point.x - rotatedRect.center.x) * (point.x - rotatedRect.center.x) + ( point.y - rotatedRect.center.y) * ( point.y - rotatedRect.center.y ) );
auto err = disToCtr - rotatedRect.size.width / ;
if ( fabs ( err ) < tolerance ) {
vecResult.push_back(point);
}
}
return vecResult;
} /* The ransac algorithm is from paper "Random Sample Consensus: A Paradigm for Model Fitting with Apphcatlons to Image Analysis and Automated Cartography".
* Given a model that requires a minimum of n data points to instantiate
* its free parameters, and a set of data points P such that the number of
* points in P is greater than n, randomly select a subset S1 of
* n data points from P and instantiate the model. Use the instantiated
* model M1 to determine the subset S1* of points in P that are within
* some error tolerance of M1. The set S1* is called the consensus set of
* S1.
* If g (S1*) is greater than some threshold t, which is a function of the
* estimate of the number of gross errors in P, use S1* to compute
* (possibly using least squares) a new model M1* and return.
* If g (S1*) is less than t, randomly select a new subset S2 and repeat the
* above process. If, after some predetermined number of trials, no
* consensus set with t or more members has been found, either solve the
* model with the largest consensus set found, or terminate in failure. */
cv::RotatedRect FitCircleRansac(const std::vector<cv::Point2f> &vecPoints, float tolerance, int maxRansacTime, int nFinishThreshold)
{
cv::RotatedRect fitResult;
if (vecPoints.size() < )
return fitResult; int nRansacTime = ;
const int RANSAC_CIRCLE_POINT = ;
size_t nMaxConsentNum = ; while ( nRansacTime < maxRansacTime ) {
std::vector<cv::Point2f> vecSelectedPoints = randomSelectPoints ( vecPoints, RANSAC_CIRCLE_POINT );
cv::RotatedRect rectReult = FitCircle ( vecSelectedPoints );
vecSelectedPoints = findPointsInTol ( vecPoints, rectReult, tolerance ); if ( vecSelectedPoints.size() >= (size_t)nFinishThreshold ) {
return FitCircle ( vecSelectedPoints );
}
else if ( vecSelectedPoints.size() > nMaxConsentNum )
{
fitResult = FitCircle ( vecSelectedPoints );
nMaxConsentNum = vecSelectedPoints.size();
}
++ nRansacTime;
} return fitResult;
} void TestFitCircle()
{
std::vector<cv::Point2f> vecPoints;
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(2.9f, 2.9f));
vecPoints.push_back(cv::Point2f(17.07f, 17.07f));
vecPoints.push_back(cv::Point2f(.f, .f));
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(, ));
vecPoints.push_back(cv::Point2f(, )); cv::RotatedRect rectResult;
rectResult = FitCircle(vecPoints); cout << " X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl; rectResult = FitCircleIterate ( vecPoints, , );
cout << "Iterator Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl; rectResult = FitCircleRansac ( vecPoints, , , );
cout << "Ransac Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl;
}
Modified Least Square Method and Ransan Method to Fit Circle from Data的更多相关文章
- 【Go入门教程5】面向对象(method、指针作为receiver、method继承、method重写)
前面两章我们介绍了函数和struct,那你是否想过函数当作struct的字段一样来处理呢?今天我们就讲解一下函数的另一种形态,带有接收者(receiver)的函数,我们称为method method ...
- 关于.ToList(): LINQ to Entities does not recognize the method ‘xxx’ method, and this method cannot be translated into a store expression.
LINQ to Entities works by translating LINQ queries to SQL queries, then executing the resulting quer ...
- java代码中init method和destroy method的三种使用方式
在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...
- Invalid character found in method name. HTTP method names must be tokens
o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header Note: further occurrenc ...
- SpringBoot:Invalid character found in method name. HTTP method names must be tokens
问题背景 关于SpringBoot应用挂了很久之后,会发生Invalid character found in method name. HTTP method names must be token ...
- Day04 -玩弄Ruby的方法:instance method与class method
前情提要在第三天时,我们解说了如何在class里用include与extend,去使用module的method. Include is for adding methods to an instan ...
- tomcat 启动报错 Invalid character found in method name. HTTP method names must be tokens
解决:Invalid character found in method name. HTTP method names must be tokens 阿里云上弄了一个tomcat,经常半夜发送崩 ...
- [Python] Python 之 function, unbound method 和 bound method
首先看一下以下示例.(Python 2.7) #!/usr/bin/env python # -*- coding: utf-8 -*- class C(object): def foo(self): ...
- 【Go入门教程7】面向对象(method、指针作为receiver、method继承、method重写)
前面两章我们介绍了函数和struct,那你是否想过函数当作struct的字段一样来处理呢?今天我们就讲解一下函数的另一种形态,带有接收者(receiver)的函数,我们称为method method ...
随机推荐
- selenium设置Chrome
关闭图片 from selenium import webdriver options = webdriver.ChromeOptions() prefs = { 'profile.default_c ...
- Android应用开发-Activity(重制版)
Android四大组件:Activity,Service,Broadcast Receiver,Content Provider Activity是Context的子类,同时实现了Window.Cal ...
- Beta版本冲刺——day5
No Bug 031402401鲍亮 031402402曹鑫杰 031402403常松 031402412林淋 031402418汪培侨 031402426许秋鑫 站立式会议 今日计划表 人员 工作 ...
- asp.net gridview 鼠标悬浮提示信息
使用场景: gridview绑定数据,某列数据太多,故超过一定字符,隐藏起来,同时鼠标移到指定列显示其明细信息: 知识点: 1,oderListTbl_DataBound事件中,添加,oderList ...
- 实践总结 - 不可错过的Angular应用技巧
angular的核心思想是通过数据驱动一切,其他东西都是数据的延伸. 套用Javascript一切皆对象的思想,在angular中可以说一切皆数据. 关于项目构建 (1) requirejs以及Yeo ...
- JAVA代码发送邮件示例和解释
下载和上传附件.发送短信和发送邮件,都算是程序中很常用的功能,之前记录了文件的上传和下载还有发送短信,由于最近比较忙,邮件发送的功能就没有时间去弄,好在昨晚终于走通代码成功以163邮箱发送邮件到qq邮 ...
- git push error: A Contributor Agreement must be completed before uploading
因为是从官方版本库做的镜像,所以有些权限直接从官方同步到了本地. 今天,有同事执行git push操作,报错: 根据网上搜索的内容,在gerrit.config中[auth]中添加如下内容: [aut ...
- TensorFlow中权重的随机初始化
一开始没看懂stddev是什么参数,找了一下,在tensorflow/python/ops里有random_ops,其中是这么写的: def random_normal(shape, mean=0.0 ...
- C# 进程间通信之二传递复杂数据类型(转)
从C#下使用WM_COPYDATA传输数据说到Marshal的应用 笔者曾在一个项目的实施过程中,需要使用WM_COPYDATA在本地机器的两个进程间传输数据.在C++中实现非常简单,但在C#中实现时 ...
- C++ 快排
// 进行一轮快排并返回当前的中间数 int getMiddle( int* arr, int low, int high ) { auto swaparr = [&]( int i, int ...