首页 > 代码库 > 直线拟合算法(续)

直线拟合算法(续)

直线拟合算法(续)

曾经写过一篇博客。介绍直线拟合算法。

http://blog.csdn.net/liyuanbhu/article/details/50866802

给出的代码事实上有一点小问题,就是 den = 0 时会出现除以 0 的错误。

今天正好也有网友问起这个问题。

我就再写一篇短文来说说怎样解决问题。

首先我们知道:

den=D2xy+(λ?Dxx)2??????????????
<script id="MathJax-Element-1" type="math/tex; mode=display"> den = \sqrt{D_{xy}^2+(\lambda-D_{xx})^2} </script>

那么 den=0<script id="MathJax-Element-2" type="math/tex">den = 0</script> 意味着:

Dxy=0λ=Dxx
<script id="MathJax-Element-3" type="math/tex; mode=display"> D_{xy} = 0\\lambda = D_{xx} </script>

我们还有关于 λ<script id="MathJax-Element-4" type="math/tex">\lambda</script> 的计算式:

λ=Dxx+Dyy?(Dxx?Dyy)2+4D2xy?????????????????2
<script id="MathJax-Element-5" type="math/tex; mode=display"> \lambda = \frac{D_{xx}+D_{yy}-\sqrt{(D_{xx}-D_{yy})^2+4D_{xy}^2}}{2} </script>

带入后得到:

Dyy?Dxx=|Dyy?Dxx|
<script id="MathJax-Element-6" type="math/tex; mode=display"> D_{yy} - D_{xx} = |D_{yy}-D_{xx}| </script>
也就是要求DyyDxx<script id="MathJax-Element-7" type="math/tex"> D_{yy} \geq D_{xx}</script>。

有了这些就能够分析分析了。

Dxy=0<script id="MathJax-Element-8" type="math/tex">D_{xy} = 0</script> 说明xi<script id="MathJax-Element-9" type="math/tex">x_i</script> 和yi<script id="MathJax-Element-10" type="math/tex">y_i</script>是线性无关的。再往下还能够细分为 2 种情况。

  1. Dyy>Dxx<script id="MathJax-Element-11" type="math/tex">D_{yy} > D_{xx}</script> 这时数据点落在一条垂直直线上,直线方程为 x=xˉ<script id="MathJax-Element-12" type="math/tex">x = \bar x</script>。
  2. Dyy=Dxx<script id="MathJax-Element-13" type="math/tex">D_{yy} = D_{xx}</script> 数据均匀分布,找不到特殊的方向,无法拟合直线方程。

依照这个分析。我们能够改进我们的代码:

bool lineFit(const std::vector<cv::Point> &points, double &a, double &b, double &c)
{
     int size = points.size();
     if(size < 2)
     {
         a = 0;
         b = 0;
         c = 0;
         return false;
     }
     double x_mean = 0;
     double y_mean = 0;

     for(int i = 0; i < size; i++)
     {
         x_mean += points[i].x;
         y_mean += points[i].y;
     }
     x_mean /= size;
     y_mean /= size; //至此。计算出了 x y 的均值

     double Dxx = 0, Dxy = 0, Dyy = 0;

     for(int i = 0; i < size; i++)
     {
         Dxx += (points[i].x - x_mean) * (points[i].x - x_mean);
         Dxy += (points[i].x - x_mean) * (points[i].y - y_mean);
         Dyy += (points[i].y - y_mean) * (points[i].y - y_mean);
     }

     double lambda = ( (Dxx + Dyy) - sqrt( (Dxx - Dyy) * (Dxx - Dyy) + 4 * Dxy * Dxy) ) / 2.0;
     double den = sqrt( Dxy * Dxy + (lambda - Dxx) * (lambda - Dxx) );

     if(fabs(den) < 1e-5)
     {
         if( fabs(Dxx / Dyy - 1) < 1e-5) //这时没有一个特殊的直线方向,无法拟合
         {
             return false;
         }
         else
         {
             a = 1;
             b = 0;
             c = - x_mean;
         }
     }
     else
     {
         a = Dxy / den;
         b = (lambda - Dxx) / den;
         c = - a * x_mean - b * y_mean;
     }
     return true;
}
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

直线拟合算法(续)