拟合一条直线到2D或3D点集。
fitLine 函数通过最小化 ∑ i ρ ( r i ) \sum_i \rho(r_i) ∑iρ(ri)来拟合一条直线到2D或3D点集,其中 r i r_i ri 是第i 个点到直线的距离,而 ρ ( r ) \rho(r) ρ(r)是一个距离函数,可以是以下之一:
DIST_L2
ρ ( r ) = r 2 / 2 (the simplest and the fastest least-squares method) \rho (r) = r^2/2 \quad \text{(the simplest and the fastest least-squares method)} ρ(r)=r2/2(the simplest and the fastest least-squares method)
DIST_L1
ρ ( r ) = r \rho (r) = r ρ(r)=r
DIST_L12
ρ ( r ) = 2 ⋅ ( 1 + r 2 2 − 1 ) \rho (r) = 2 \cdot ( \sqrt{1 + \frac{r^2}{2}} - 1) ρ(r)=2⋅(1+2r2−1)
DIST_FAIR
ρ ( r ) = C 2 ⋅ ( r C − log ( 1 + r C ) ) where C = 1.3998 \rho \left (r \right ) = C^2 \cdot \left ( \frac{r}{C} - \log{\left(1 + \frac{r}{C}\right)} \right ) \quad \text{where} \quad C=1.3998 ρ(r)=C2⋅(Cr−log(1+Cr))whereC=1.3998
DIST_WELSCH
ρ ( r ) = C 2 2 ⋅ ( 1 − exp ( − ( r C ) 2 ) ) where C = 2.9846 \rho \left (r \right ) = \frac{C^2}{2} \cdot \left ( 1 - \exp{\left(-\left(\frac{r}{C}\right)^2\right)} \right ) \quad \text{where} \quad C=2.9846 ρ(r)=2C2⋅(1−exp(−(Cr)2))whereC=2.9846
DIST_HUBER
ρ ( r ) = { r 2 2 if r < C C ⋅ ( r − C 2 ) otherwise 此处 C = 1.345 \rho(r) = \begin{cases} \frac{r^2}{2} & \text{if } r < C \\ C \cdot (r - \frac{C}{2}) & \text{otherwise} \end{cases} 此处C=1.345 ρ(r)={2r2C⋅(r−2C)if r<Cotherwise此处C=1.345
该算法基于 M-估计器技术(http://en.wikipedia.org/wiki/M-estimator),该技术迭代地使用加权最小二乘法来拟合直线。在每次迭代之后,权重 w i w_i wi被调整为与 ρ ( r i ) \rho(r_i) ρ(ri)成反比。
void cv::fitLine
(
InputArray points,
OutputArray line,
int distType,
double param,
double reps,
double aeps
)
#include
#include
using namespace std;
using namespace cv;
int main()
{
// 创建一个空白图像
Mat img( 400, 400, CV_8UC3, Scalar( 255, 255, 255 ) );
// 创建一组2D点
vector< Point2f > points;
points.push_back( Point2f( 100, 100 ) );
points.push_back( Point2f( 200, 100 ) );
points.push_back( Point2f( 200, 200 ) );
points.push_back( Point2f( 100, 200 ) );
points.push_back( Point2f( 150, 150 ) );
points.push_back( Point2f( 150, 250 ) );
points.push_back( Point2f( 250, 150 ) );
points.push_back( Point2f( 250, 250 ) );
// 定义输出直线
Vec4f line;
// 拟合直线
fitLine( points, line, DIST_L2, 0, 0.01, 0.01 );
// 获取直线参数
float vx = line[ 0 ];
float vy = line[ 1 ];
float x0 = line[ 2 ];
float y0 = line[ 3 ];
// 计算两点来绘制直线
Point p1( x0 - 100 * vx, y0 - 100 * vy );
Point p2( x0 + 100 * vx, y0 + 100 * vy );
// 在原图上绘制直线
cv::line( img, p1, p2, Scalar( 0, 0, 255 ), 2, LINE_8 );
// 绘制点集
for ( const auto& pt : points )
{
circle( img, pt, 5, Scalar( 0, 255, 0 ), -1 );
}
// 显示结果
imshow( "Line Fitting", img );
waitKey( 0 );
return 0;
}