# 平行线拟合问题（附带 C++ 源代码）

#平行线拟合问题

$D^2 = \sum_{i=0}^{N_1} (a x_{1,i} + b y_{1,i} + c_1)^2 + \sum_{j=0}^{N_2} (a x_{2,j} + b y_{2,j} + c_2)^2 + \lambda (a^2 + b^2 - 1)$

$\frac{\partial D^2}{\partial c_1} = 2 \sum_{i=0}^{N_1} ( a x_{1,i} + b y_{1,i} + c_1) = 0\\ \frac{\partial D^2}{\partial c_2} = 2 \sum_{j=0}^{N_2} ( a x_{2,j} + b y_{2,j} + c_2) = 0\\$

$a \overline {x_1} + b \overline{y_1} + c_1 = 0 \\ a \overline{x_2} + b \overline{y_2} + c_2 = 0$

$p_{1,i} = x_{1,i} - \overline {x_1} \\ q_{1,i} = y_{1,i} - \overline {y_1} \\ p_{2,i} = x_{2,i} - \overline {x_2} \\ q_{2,i} = y_{2,i} - \overline {y_2}$

$D^2 = \sum_{i=0}^{N_1} (a p_{1,i} + b q_{1,i})^2 + \sum_{j=0}^{N_2} (a p_{2,j} + b q_{2,j})^2 - \lambda (a^2 + b^2 - 1)$

$D^2 = \sum_{i=0}^{N_1 + N_2} (a x_{i} + b y_{i})^2 - \lambda (a^2 + b^2 - 1)$

$\frac{\partial D^2}{\partial a} = 2 \sum_{i=0}^{N_1 + N_2} x_{i}(a x_{i} + b y_{i}) - 2 \lambda a = 0 \\ \frac{\partial D^2}{\partial b} = 2 \sum_{i=0}^{N_1 + N_2} y_{i}(a x_{i} + b y_{i}) - 2 \lambda b = 0$

$a \sum x_i^2 + b \sum{x_i y_i} = \lambda a\\ a \sum{x_i y_i} + b \sum{y_i^2} = \lambda b$

$D_{xx} = \sum{x_i^2}, D_{xy} = \sum{x_i y_i}, D_{yy} = \sum{y_i^2}$

$D_{xx} a + D_{xy} b = \lambda a \\ D_{xy} a + D_{yy} b = \lambda b$

$\sum_{i=0}^{N} (a x_{i} + b y_{i})^2 = \left(\begin{matrix} a & b \end{matrix} \right) \left(\begin{matrix} D_{xx} & D_{xy} \\ D_{xy} & D_{yy} \end{matrix} \right) \left(\begin{matrix} a \\ b \end{matrix} \right) = \lambda$

/**
* @brief plinesFit 平行线拟合算法 最小二乘法拟合 ax + by + c = 0 型直线
* @param line1 第一条直线的数据点
* @param line2 第二条直线的数据点
* @param [out] a 输出拟合系数
* @param [out] b 输出拟合系数
* @param [out] c1 输出拟合系数，第一条直线的方程为 ax + by + c1 = 0
* @param [out] c2 输出拟合系数，第二条直线的方程为 ax + by + c2 = 0
* @return true 表示拟合成功，false 表示拟合失败
*/
bool plinesFit(const QVector<QPointF> &line1, const QVector<QPointF> &line2, double &a, double &b, double &c1, double &c2)
{

if(line1.size() < 2 ||  line2.size() < 0)
{
a = 0;
b = 0;
c1 = 0;
c2 = 0;
return false;
}
int size = line1.size();
double x_mean_1 = 0, x_mean_2 = 0;
double y_mean_1 = 0, y_mean_2 = 0;
for(int i = 0; i < size; i++)
{
x_mean_1 += line1[i].x();
y_mean_1 += line1[i].y();
}
x_mean_1 /= size;
y_mean_1 /= size; //至此，计算出了 x y 的均值

double Dxx = 0, Dxy = 0, Dyy = 0;
for(int i = 0; i < size; i++)
{
Dxx += (line1[i].x() - x_mean_1) * (line1[i].x() - x_mean_1);
Dxy += (line1[i].x() - x_mean_1) * (line1[i].y() - y_mean_1);
Dyy += (line1[i].y() - y_mean_1) * (line1[i].y() - y_mean_1);
}

size = line2.size();
for(int i = 0; i < size; i++)
{
x_mean_2 += line2[i].x();
y_mean_2 += line2[i].y();
}
x_mean_2 /= size;
y_mean_2 /= size; //至此，计算出了 x y 的均值

for(int i = 0; i < size; i++)
{
Dxx += (line2[i].x() - x_mean_2) * (line2[i].x() - x_mean_2);
Dxy += (line2[i].x() - x_mean_2) * (line2[i].y() - y_mean_2);
Dyy += (line2[i].y() - y_mean_2) * (line2[i].y() - y_mean_2);
}

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;
c1 = - x_mean_1;
c2 = - x_mean_2;

}
}
else
{
a = Dxy / den;
b = (lambda - Dxx) / den;
c1 = - a * x_mean_1 - b * y_mean_1;
c2 = - a * x_mean_2 - b * y_mean_2;

if(a < 0)
{
a = -a;
b = -b;
c1 = -c1;
c2 = -c2;
}
}
return true;
}



09-23 8852

08-19 6577

03-27 3837

12-23 9116

08-14 3807

#### 线段(向量)的计算（判断线段重叠、相交，合并线段，点与线的关系）

©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。