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".

  1. // This function is based on Modified Least Square Methods from Paper
  2. // "A Few Methods for Fitting Circles to Data".
  3. cv::RotatedRect FitCircle(const std::vector<cv::Point2f> &vecPoints)
  4. {
  5. cv::RotatedRect rotatedRect;
  6. if ( vecPoints.size() < )
  7. return rotatedRect;
  8.  
  9. double Sx = ., Sy = ., Sx2 = ., Sy2 = ., Sxy = ., Sx3 = ., Sy3 = ., Sxy2 = ., Syx2 = .;
  10. for ( const auto &point : vecPoints ) {
  11. Sx += point.x;
  12. Sy += point.y;
  13. Sx2 += point.x * point.x;
  14. Sy2 += point.y * point.y;
  15. Sxy += point.x * point.y;
  16. Sx3 += point.x * point.x * point.x;
  17. Sy3 += point.y * point.y * point.y;
  18. Sxy2 += point.x * point.y * point.y;
  19. Syx2 += point.y * point.x * point.x;
  20. }
  21.  
  22. double A, B, C, D, E;
  23. int n = vecPoints.size();
  24. A = n * Sx2 - Sx * Sx;
  25. B = n * Sxy - Sx * Sy;
  26. C = n * Sy2 - Sy * Sy;
  27. D = 0.5 * ( n * Sxy2 - Sx * Sy2 + n * Sx3 - Sx * Sx2 );
  28. E = 0.5 * ( n * Syx2 - Sy * Sx2 + n * Sy3 - Sy * Sy2 );
  29.  
  30. auto AC_B2 = ( A * C - B * B); // The variable name is from AC - B^2
  31. auto am = ( D * C - B * E ) / AC_B2;
  32. auto bm = ( A * E - B * D ) / AC_B2;
  33.  
  34. double rSqureSum = .f;
  35. for ( const auto &point : vecPoints )
  36. {
  37. rSqureSum += sqrt ( ( point.x - am ) * ( point.x - am ) + ( point.y - bm) * ( point.y - bm) );
  38. }
  39. float r = static_cast<float>( rSqureSum / n );
  40. rotatedRect.center.x = static_cast<float>( am );
  41. rotatedRect.center.y = static_cast<float>( bm );
  42. rotatedRect.size = cv::Size2f( .f * r, .f * r );
  43.  
  44. return rotatedRect;
  45. }
  46.  
  47. std::vector<size_t> findPointOverTol( const std::vector<cv::Point2f> &vecPoints, const cv::RotatedRect &rotatedRect, int method, float tolerance )
  48. {
  49. std::vector<size_t> vecResult;
  50. for ( size_t i = ;i < vecPoints.size(); ++ i ) {
  51. cv::Point2f point = vecPoints[i];
  52. auto disToCtr = sqrt( ( point.x - rotatedRect.center.x) * (point.x - rotatedRect.center.x) + ( point.y - rotatedRect.center.y) * ( point.y - rotatedRect.center.y ) );
  53. auto err = disToCtr - rotatedRect.size.width / ;
  54. if ( method == && fabs ( err ) > tolerance ) {
  55. vecResult.push_back(i);
  56. }else if ( method == && err > tolerance ) {
  57. vecResult.push_back(i);
  58. }else if ( method == && err < -tolerance ) {
  59. vecResult.push_back(i);
  60. }
  61. }
  62. return vecResult;
  63. }
  64.  
  65. //method 1 : Exclude all the points out of positive error tolerance and inside the negative error tolerance.
  66. //method 2 : Exclude all the points out of positive error tolerance.
  67. //method 3 : Exclude all the points inside the negative error tolerance.
  68. cv::RotatedRect FitCircleIterate(const std::vector<cv::Point2f> &vecPoints, int method, float tolerance)
  69. {
  70. cv::RotatedRect rotatedRect;
  71. if (vecPoints.size() < )
  72. return rotatedRect;
  73.  
  74. std::vector<cv::Point2f> vecLocalPoints;
  75. for ( const auto &point : vecPoints ) {
  76. vecLocalPoints.push_back ( point );
  77. }
  78. rotatedRect = FitCircle ( vecLocalPoints );
  79.  
  80. std::vector<size_t> overTolPoints = findPointOverTol ( vecLocalPoints, rotatedRect, method, tolerance );
  81. int nIteratorNum = ;
  82. while ( ! overTolPoints.empty() && nIteratorNum < ) {
  83. for (auto it = overTolPoints.rbegin(); it != overTolPoints.rend(); ++ it)
  84. vecLocalPoints.erase(vecLocalPoints.begin() + *it);
  85. rotatedRect = FitCircle ( vecLocalPoints );
  86. overTolPoints = findPointOverTol ( vecLocalPoints, rotatedRect, method, tolerance );
    ++ nIteratorNum;
  87. }
  88. return rotatedRect;
  89. }
  90.  
  91. std::vector<cv::Point2f> randomSelectPoints(const std::vector<cv::Point2f> &vecPoints, int needToSelect)
  92. {
  93. std::set<int> setResult;
  94. std::vector<cv::Point2f> vecResultPoints;
  95.  
  96. if ( (int)vecPoints.size() < needToSelect )
  97. return vecResultPoints;
  98.  
  99. while ((int)setResult.size() < needToSelect) {
  100. int nValue = std::rand() % vecPoints.size();
  101. setResult.insert(nValue);
  102. }
  103. for ( auto index : setResult )
  104. vecResultPoints.push_back ( vecPoints[index] );
  105. return vecResultPoints;
  106. }
  107.  
  108. std::vector<cv::Point2f> findPointsInTol( const std::vector<cv::Point2f> &vecPoints, const cv::RotatedRect &rotatedRect, float tolerance )
  109. {
  110. std::vector<cv::Point2f> vecResult;
  111. for ( const auto &point : vecPoints ) {
  112. auto disToCtr = sqrt( ( point.x - rotatedRect.center.x) * (point.x - rotatedRect.center.x) + ( point.y - rotatedRect.center.y) * ( point.y - rotatedRect.center.y ) );
  113. auto err = disToCtr - rotatedRect.size.width / ;
  114. if ( fabs ( err ) < tolerance ) {
  115. vecResult.push_back(point);
  116. }
  117. }
  118. return vecResult;
  119. }
  120.  
  121. /* The ransac algorithm is from paper "Random Sample Consensus: A Paradigm for Model Fitting with Apphcatlons to Image Analysis and Automated Cartography".
  122. * Given a model that requires a minimum of n data points to instantiate
  123. * its free parameters, and a set of data points P such that the number of
  124. * points in P is greater than n, randomly select a subset S1 of
  125. * n data points from P and instantiate the model. Use the instantiated
  126. * model M1 to determine the subset S1* of points in P that are within
  127. * some error tolerance of M1. The set S1* is called the consensus set of
  128. * S1.
  129. * If g (S1*) is greater than some threshold t, which is a function of the
  130. * estimate of the number of gross errors in P, use S1* to compute
  131. * (possibly using least squares) a new model M1* and return.
  132. * If g (S1*) is less than t, randomly select a new subset S2 and repeat the
  133. * above process. If, after some predetermined number of trials, no
  134. * consensus set with t or more members has been found, either solve the
  135. * model with the largest consensus set found, or terminate in failure. */
  136. cv::RotatedRect FitCircleRansac(const std::vector<cv::Point2f> &vecPoints, float tolerance, int maxRansacTime, int nFinishThreshold)
  137. {
  138. cv::RotatedRect fitResult;
  139. if (vecPoints.size() < )
  140. return fitResult;
  141.  
  142. int nRansacTime = ;
  143. const int RANSAC_CIRCLE_POINT = ;
  144. size_t nMaxConsentNum = ;
  145.  
  146. while ( nRansacTime < maxRansacTime ) {
  147. std::vector<cv::Point2f> vecSelectedPoints = randomSelectPoints ( vecPoints, RANSAC_CIRCLE_POINT );
  148. cv::RotatedRect rectReult = FitCircle ( vecSelectedPoints );
  149. vecSelectedPoints = findPointsInTol ( vecPoints, rectReult, tolerance );
  150.  
  151. if ( vecSelectedPoints.size() >= (size_t)nFinishThreshold ) {
  152. return FitCircle ( vecSelectedPoints );
  153. }
  154. else if ( vecSelectedPoints.size() > nMaxConsentNum )
  155. {
  156. fitResult = FitCircle ( vecSelectedPoints );
  157. nMaxConsentNum = vecSelectedPoints.size();
  158. }
  159. ++ nRansacTime;
  160. }
  161.  
  162. return fitResult;
  163. }
  164.  
  165. void TestFitCircle()
  166. {
  167. std::vector<cv::Point2f> vecPoints;
  168. vecPoints.push_back(cv::Point2f(, ));
  169. vecPoints.push_back(cv::Point2f(2.9f, 2.9f));
  170. vecPoints.push_back(cv::Point2f(17.07f, 17.07f));
  171. vecPoints.push_back(cv::Point2f(.f, .f));
  172. vecPoints.push_back(cv::Point2f(, ));
  173. vecPoints.push_back(cv::Point2f(, ));
  174. vecPoints.push_back(cv::Point2f(, ));
  175. vecPoints.push_back(cv::Point2f(, ));
  176. vecPoints.push_back(cv::Point2f(, ));
  177. vecPoints.push_back(cv::Point2f(, ));
  178.  
  179. cv::RotatedRect rectResult;
  180. rectResult = FitCircle(vecPoints);
  181.  
  182. cout << " X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl;
  183.  
  184. rectResult = FitCircleIterate ( vecPoints, , );
  185. cout << "Iterator Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl;
  186.  
  187. rectResult = FitCircleRansac ( vecPoints, , , );
  188. cout << "Ransac Result X, Y " << rectResult.center.x << ", " << rectResult.center.y << " r " << rectResult.size.width / . << endl;
  189. }

Modified Least Square Method and Ransan Method to Fit Circle from Data的更多相关文章

  1. 【Go入门教程5】面向对象(method、指针作为receiver、method继承、method重写)

    前面两章我们介绍了函数和struct,那你是否想过函数当作struct的字段一样来处理呢?今天我们就讲解一下函数的另一种形态,带有接收者(receiver)的函数,我们称为method method ...

  2. 关于.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 ...

  3. java代码中init method和destroy method的三种使用方式

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...

  4. 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 ...

  5. 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 ...

  6. Day04 -玩弄Ruby的方法:instance method与class method

    前情提要在第三天时,我们解说了如何在class里用include与extend,去使用module的method. Include is for adding methods to an instan ...

  7. 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,经常半夜发送崩 ...

  8. [Python] Python 之 function, unbound method 和 bound method

    首先看一下以下示例.(Python 2.7) #!/usr/bin/env python # -*- coding: utf-8 -*- class C(object): def foo(self): ...

  9. 【Go入门教程7】面向对象(method、指针作为receiver、method继承、method重写)

    前面两章我们介绍了函数和struct,那你是否想过函数当作struct的字段一样来处理呢?今天我们就讲解一下函数的另一种形态,带有接收者(receiver)的函数,我们称为method method ...

随机推荐

  1. knockout+bootstrap--一些复杂的应用合集

    一.针对My97日历控件的绑定 普通绑定和特殊格式绑定(红色部分) <!-- ko foreach: items --> <td class="ruyeeTableTDLa ...

  2. 怎么查看bios版本

    怎么查看bios版本呢?无需去注册表查看,无需去BIOS中查看,只需要一条简单的命令即可,下面就来一起看一看怎么查看bios版本: Win键+R打开“运行”,然后再“运行”中输入cmd进而打开“cmd ...

  3. ife-task0003学习收获总结

    + 编写可维护的css原则是,尽量减少改动时要编辑的地方(减少代码重复). + CSS布局奇淫技巧之-高度自适应 高度自适应:通过绝对定位来解决高度自适应的问题,元素不设置高度,设置绝对定位,将top ...

  4. modelsim操作流程

    1.File->Change Directory2.File->New->Library 在弹出的对话框中选择 a new library and a logical mapping ...

  5. Tomcat启动报错 Could not reserve enough space for object heap

    报错信息: Error occurred during initialization of VM Could not reserve enough space for object heap Coul ...

  6. mfc release 版本 内存不足 的解决方法

  7. 轨迹记录App是怎样对定位轨迹进行过滤、优化和平滑处理的

    https://www.zhihu.com/question/39983016 卡尔曼滤波原理 卡尔曼滤波学习笔记 卡尔曼滤波的原理说明 http://www.cs.unc.edu/~welch/ka ...

  8. UVA 1151 买还是建(最小生成树)

    买还是建 紫书P358 [题目链接]买还是建 [题目类型]最小生成树 &题解: 这题真的心累,看了3天,最后照着码还是wa,先放lrj代码,以后再看吧 &代码: // UVa1151 ...

  9. shell script

    一.shell script的编写与执行 1.shell script 的编写中还需要用到下面的注意事项: a.命令的执行是从上到下,从左到右地分析与执行 b.命令.参数间的多个空白都会被忽略掉 c. ...

  10. linux查找日志技巧

    对于从事web开发的人员来说.服务器上的日志多如牛毛,如何快速从中找出所需信息非常重要,以下是我在工作中用到的查找日志的简单命令,希望能对您有所帮助:   工具/原料   linux SecureCR ...