点集的直线拟合 - 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 是你在画椭圆时会用到的函数之一。

⚠️ **GitHub.com Fallback** ⚠️