点集的直线拟合 - sumpig/OpenCV GitHub Wiki
在某些应用程序中,光是检测出图像中的直线还不够,还需要精确地估计直线的位置和方向。本节将介绍如何拟合出最适合指定点集的直线。
首先需要识别出图像中靠近直线的点。为了提取出靠近这条直线(我们叫它第一条直线)的点集,可以继续以下步骤:在黑色图像上画一条白色直线,并且 穿过用于检测直线的Canny 轮廓图。
int n=0; // 选用直线0
// 黑色图像
cv::Mat oneline(contours.size(), CV_8U, cv::Scalar(0));
// 白色直线
cv::line(oneline,
cv::Point(lines[n][0], lines[n][1]),
cv::Point(lines[n][2], lines[n][3]),
cv::Scalar(255),
3); // 直线宽度
// 轮廓与白色直线进行“与”运算
cv::bitwise_and(contours,oneline,oneline);
然后提取这些点集。
std::vector<cv::Point> points;
// 迭代遍历像素,得到所有点的位置
for(int y=0; y<oneline.rows; y++ ) {
// 行y
uchar* rowPtr = oneline.ptr<uchar>(y);
for(int x=0; x<oneline.cols; x++) {
// 如果在轮廓上
if (rowPtr[x])
points.push_back(cv::Point(x,y));
}
}
得到点集后,利用 OpenCV 的函数 cv::fitLine 可以很轻松地得到最优的拟合直线:
cv::Vec4f line;
cv::fitLine(points,line,
cv::DIST_L2, // 距离类型
0, // L2 距离不用这个参数
0.01, 0.01); // 精度
OpenCV 的实现方法是使每个点到直线的距离之和最小化。在众多用于计算距离的函数中,欧几里得距离的计算速度最快。
我们也可以用这个函数在三维点集上拟合直线。这时输入的是 cv::Point3i 或 cv::Point3f 对象的集合,输出的是一个 std::Vec6f 实例。
cv::fitEllipse 函数在二维点集上拟合一个椭圆。它返回一个旋转的矩形(一个 cv::RotatedRect 实例),矩形中有一个内切的椭圆。
cv::RotatedRect rrect= cv::fitEllipse(cv::Mat(points));
cv::ellipse(image, rrect, cv::Scalar(0));
cv::ellipse 是你在画椭圆时会用到的函数之一。