博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Modified Least Square Method and Ransan Method to Fit Circle from Data
阅读量:4628 次
发布时间:2019-06-09

本文共 8040 字,大约阅读时间需要 26 分钟。

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
&vecPoints){ cv::RotatedRect rotatedRect; if ( vecPoints.size() < 3 ) return rotatedRect; double Sx = 0., Sy = 0., Sx2 = 0., Sy2 = 0., Sxy = 0., Sx3 = 0., Sy3 = 0., Sxy2 = 0., Syx2 = 0.; 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 = 0.f; for ( const auto &point : vecPoints ) { rSqureSum += sqrt ( ( point.x - am ) * ( point.x - am ) + ( point.y - bm) * ( point.y - bm) ); } float r = static_cast
( rSqureSum / n ); rotatedRect.center.x = static_cast
( am ); rotatedRect.center.y = static_cast
( bm ); rotatedRect.size = cv::Size2f( 2.f * r, 2.f * r ); return rotatedRect;}std::vector
findPointOverTol( const std::vector
&vecPoints, const cv::RotatedRect &rotatedRect, int method, float tolerance ){ std::vector
vecResult; for ( size_t i = 0;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 / 2; if ( method == 1 && fabs ( err ) > tolerance ) { vecResult.push_back(i); }else if ( method == 2 && err > tolerance ) { vecResult.push_back(i); }else if ( method == 3 && 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
&vecPoints, int method, float tolerance){ cv::RotatedRect rotatedRect; if (vecPoints.size() < 3) return rotatedRect; std::vector
vecLocalPoints; for ( const auto &point : vecPoints ) { vecLocalPoints.push_back ( point ); } rotatedRect = FitCircle ( vecLocalPoints ); std::vector
overTolPoints = findPointOverTol ( vecLocalPoints, rotatedRect, method, tolerance ); int nIteratorNum = 1; while ( ! overTolPoints.empty() && nIteratorNum < 20 ) { 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
randomSelectPoints(const std::vector
&vecPoints, int needToSelect){ std::set
setResult; std::vector
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
findPointsInTol( const std::vector
&vecPoints, const cv::RotatedRect &rotatedRect, float tolerance ){ std::vector
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 / 2; 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
&vecPoints, float tolerance, int maxRansacTime, int nFinishThreshold){ cv::RotatedRect fitResult; if (vecPoints.size() < 3) return fitResult; int nRansacTime = 0; const int RANSAC_CIRCLE_POINT = 3; size_t nMaxConsentNum = 0; while ( nRansacTime < maxRansacTime ) { std::vector
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
vecPoints; vecPoints.push_back(cv::Point2f(0, 10)); vecPoints.push_back(cv::Point2f(2.9f, 2.9f)); vecPoints.push_back(cv::Point2f(17.07f, 17.07f)); vecPoints.push_back(cv::Point2f(3.f, 8.f)); vecPoints.push_back(cv::Point2f(10, 0)); vecPoints.push_back(cv::Point2f(10, 20)); vecPoints.push_back(cv::Point2f(11, 18)); vecPoints.push_back(cv::Point2f(20, 10)); vecPoints.push_back(cv::Point2f(28, 18)); vecPoints.push_back(cv::Point2f(17, 9)); cv::RotatedRect rectResult; rectResult = FitCircle(vecPoints); cout << " X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / 2. << endl; rectResult = FitCircleIterate ( vecPoints, 2, 2 ); cout << "Iterator Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / 2. << endl; rectResult = FitCircleRansac ( vecPoints, 1, 20, 7 ); cout << "Ransac Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / 2. << endl;}

 

转载于:https://www.cnblogs.com/shengguang/p/5889172.html

你可能感兴趣的文章
移动端rem屏幕设置
查看>>
4.0 C++远征:重载运算符
查看>>
每天写的叫工作日志,每周写的总结叫周报,每月写的叫月报
查看>>
codeforces 985 D. Sand Fortress(二分+思维)
查看>>
使用locate 的正则查询 查找所有main.c
查看>>
hive基本操作与应用
查看>>
C# 视频多人脸识别的实现
查看>>
ACdream 1099——瑶瑶的第K大——————【快排舍半,输入外挂】
查看>>
Leetcode:Count and Say
查看>>
jQuery中getJSON跨域原理详解
查看>>
洛谷——P2341 [HAOI2006]受欢迎的牛//POJ2186:Popular Cows
查看>>
WebKit、Gecko使用图形库
查看>>
babel
查看>>
JVM GC 垃圾回收(二)之 判断那些可回收,怎么回收
查看>>
图片模糊处理
查看>>
oracle 如何预估将要创建的索引的大小
查看>>
剑指Offer——平衡二叉树
查看>>
链式前向星(模板)
查看>>
第八周周总结
查看>>
【转】Word2007中不连续页码设置 多种页码设置
查看>>