OpenCV学习(直线拟合)

OpenCV学习(直线拟合
OpenCV 学习(直线拟合)
Hough 变换可以提取图像中的直线。但是提取的直线的精度不⾼。⽽很多场合下,我们需要精确的估计直线的参数,这时就需要进⾏直线拟合。
直线拟合的⽅法很多,⽐如⼀元线性回归就是⼀种最简单的直线拟合⽅法。但是这种⽅法不适合⽤于提取图像中的直线。因为这种算法假设每个数据点的X 坐标是准确的,Y 坐标是带有⾼斯噪声的。可实际上,图像中的每个数据点的XY 坐标都是带有噪声的。
下⾯就来讲讲适⽤于提取图像中直线的直线拟合算法。
⼀个点 到直线的距离⽤ 来表⽰。
所谓直线拟合,就是到⼀条直线,使得:
最⼩。
是距离函数。 函数取不同的形式,对应不同的直线拟合⽅法。OpenCV 中⽀持 6 种不同的 函数形式。分别是:
CV_DIST_L2
这种⽅法是以距离平⽅和为拟合判据。也就是常见的最⼩⼆乘拟合算法,运⾏速度也最快。但是这个算法也有个很⼤的问题,就是当⼲扰点离直线较远时,⼀个⼲扰点就可能将整条拟合直线拉偏了。简单的说就是对⼲扰点的鲁棒性不够。所以后来⼜提出了其他的函数。
CV_DIST_L1
CV_DIST_L12
CV_DIST_FAIR
其中 C = 1.3998
CV_DIST_WELSCH
其中 C = 2.9846
CV_DIST_HUBER
其中 C = 1.345
后⾯这 5 种函数我知道第⼀种,其他的不知道是怎么来的。OpenCV 的帮助⽂档给出了⼀个链接:
但是这个页⾯也被墙了。
下⾯来说说 OpenCV 提供的直线拟合函数。函数原型如下:
void fitLine( InputArray points,
OutputArray line,
int distType,
double param,
double reps,
double aeps );
distType 指定拟合函数的类型,可以取 CV_DIST_L2、CV_DIST_L1、CV_DIST_L12、CV_DIST_FAIR、CV_DIST_WELSCH、
CV_DIST_HUBER。
param 就是 CV_DIST_FAIR、CV_DIST_WELSCH、CV_DIST_HUBER 公式中的C。如果取 0,则程序⾃动选取合适的值。
reps 表⽰直线到原点距离的精度,建议取 0.01。
aeps 表⽰直线⾓度的精度,建议取 0.01。
计算出的直线信息存放在 line 中,为 cv::Vec4f 类型。line[0]、line[1] 存放的是直线的⽅向向量。line[2]、line[3] 存放的是直线上⼀个点的坐标。
如果直线⽤ 来表⽰,那么 k = line[1]/line[0],b = line[3] - k * line[2]。
如果直线⽤ 来表⽰, 那么
下⾯是个测试图像:
图像中有⼀条直线和⼀些⼲扰图案。
下⾯的代码可以从图像中提取出需要的坐标点。下⾯的代码可以在图中画⼀条直线。
std::vector <cv::Point> getPoints(cv::Mat &image, int  value)
{
int  nl = ws; // number of lines
int  nc = ls * image.channels();
std::vector <cv::Point> points;
for  (int  j = 0; j < nl; j++)
{
uchar* data = image.ptr<uchar>(j);
for  (int  i = 0; i < nc; i++)
{
if (data[i] == value)
{
points.push_back(cv::Point(i, j));
}
}
}
return  points;
}
void drawLine(cv::Mat &image, double theta, double rho, cv::Scalar color)
{
if (theta < PI/4. || theta > 3.*PI/4.)// ~vertical line
{
cv::Point pt1(rho/cos(theta), 0);
cv::Point pt2((rho - ws * sin(theta))/cos(theta), ws);
cv::line( image, pt1, pt2, cv::Scalar(255), 1);
}
else
{
cv::Point pt1(0, rho/sin(theta));
cv::Point ls, (rho - ls * cos(theta))/sin(theta));
cv::line(image, pt1, pt2, color, 1);
}
}
下⾯的代码是程序的主体。
int main(int argc, char *argv[])
拟合直线
{
QCoreApplication a(argc, argv);
cv::Mat image = imread("c:\\line_test.png", cv::IMREAD_GRAYSCALE);
std::vector<cv::Point> points = getPoints(image, 0);
cv::Vec4f line;
cv::fitLine(points,
line,
CV_DIST_HUBER  ,
0,
0.01,
0.01);
double cos_theta = line[0];
double sin_theta = line[1];
double x0 = line[2], y0 = line[3];
double phi = atan2(sin_theta, cos_theta) + PI / 2.0;
double rho = y0 * cos_theta - x0 * sin_theta;
std::cout << "phi = " << phi / PI * 180 << std::endl;
std::cout << "rho = " << rho << std::endl;
drawLine(image, phi, rho, cv::Scalar(0));
double k = sin_theta / cos_theta;
double b = y0 - k * x0;
double x = 0;
double y = k * x + b;
std::cout << k << std::endl;
std::cout << b << std::endl;
//cv::line(image, Point(x0,y0), Point(x,y), cv::Scalar(255), 1);
imshow("", image);
();
}
如果直线拟合类型选择 CV_DIST_L2。那么效果就没这么好了。代码不贴了,就贴个结果。

本文发布于:2024-09-22 07:09:36,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/359929.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:直线   拟合   函数   提取   图像   需要
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议