OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合

这篇具有很好参考价值的文章主要介绍了OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.  椭圆拟合

轮廓的椭圆拟合是指用椭圆来近似轮廓的形状。当这个椭圆的长轴和短轴相等时,它就是一个圆。

椭圆拟合的基本思路是:对于给定平面上的一组样本点,寻找一个椭圆,使其尽可能接近这些样本点。也就是说,将图像中的一组数据以椭圆方程为模型进行拟合,使某一椭圆方程尽量满足这些数据,并求出该椭圆方程的各个参数。

椭圆拟合有以下几种常用方法:

  • 最小二乘法:最小二乘法是基于最小化拟合误差的思想,通过迭代的方法求解椭圆参数。该方法的优点是简单易实现,缺点是计算量大,当轮廓点数较多时,容易出现收敛问题。

  • 极大似然法:极大似然法是基于概率统计的思想,通过最大化椭圆模型的似然函数求解椭圆参数。该方法的优点是收敛速度快,计算量小,缺点是对初始值敏感。

  • 最小距离法:最小距离法是基于最小化样本点到椭圆的距离的思想,通过迭代的方法求解椭圆参数。该方法的优点是计算量小,收敛速度快,缺点是对初始值敏感。

在 OpenCV 提供了三种 fitEllipse()、fitEllipseAMS()、fitEllipseDirect() 函数实现椭圆拟合。

RotatedRect fitEllipse( InputArray points );

RotatedRect fitEllipseAMS( InputArray points );

RotatedRect fitEllipseDirect( InputArray points );

其输出的 RotatedRect 包含了

  • 椭圆的中心位置

  • 长轴的直径

  • 短轴的直径

  • 旋转角度

OpenCV 提供的这三个函数还是有一定区别的:

函数 算法 优点 缺点
fitEllipse() 最小二乘法 简单易实现 计算量大,收敛问题
fitEllipseAMS() 改进的最小二乘法 收敛速度快,精度高 计算量略大
fitEllipseDirect() 直接求解 计算量最小 对初始值敏感

在实际应用中,可以根据具体情况选择合适的椭圆拟合函数。如果对拟合精度要求较高,可以使用 fitEllipseAMS() 函数。如果对计算速度要求较高,可以使用 fitEllipseDirect() 函数。

下面的例子展示了找到有效的轮廓后,对这些轮廓进行椭圆拟合。

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace std;
using namespace cv;

bool ascendSort(vector<Point> a,vector<Point> b)
{
    return contourArea(a) > contourArea(b);
}

int main(int argc, char **argv) {
    Mat src = imread(".../test.jpg");
    imshow("src", src);

    Mat gray,thresh;
    cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    threshold(gray,thresh,0,255,THRESH_BINARY_INV | THRESH_OTSU);
    imshow("thresh", thresh);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(thresh, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    sort(contours.begin(), contours.end(), ascendSort);//ascending sort

    for (size_t i = 0; i< contours.size(); i++) {
        double area = contourArea(contours[i]);

        if (area < 1000) {
            continue;
        }

        RotatedRect rrt = fitEllipse(contours[i]);
        Point2f center = rrt.center;
        float w = rrt.size.width;
        float h = rrt.size.height;
        float angle = rrt.angle;
        printf("w = %f, h = %f , angle = %f\n",w,h,angle);
        ellipse(src,rrt, Scalar(0, 255, 255), 8, 8);
    }
    imshow("result", src);

    waitKey(0);
    return 0;
}

执行结果:

w = 172.647202, h = 569.465088 , angle = 76.293610
w = 174.775482, h = 544.108643 , angle = 134.146057
w = 172.592422, h = 589.588135 , angle = 175.138290
w = 178.092865, h = 536.354919 , angle = 154.063202
w = 170.954330, h = 539.261047 , angle = 113.472153
w = 166.067673, h = 571.457947 , angle = 45.668461
w = 162.812332, h = 559.349915 , angle = 97.494217
w = 149.240463, h = 615.341309 , angle = 20.167418
w = 152.298386, h = 594.066528 , angle = 11.754380
w = 144.079239, h = 591.841553 , angle = 69.640686
w = 154.095871, h = 518.927307 , angle = 42.097614
OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合,opencv,笔记,人工智能,计算机视觉
椭圆拟合.png

2.  直线拟合

轮廓的直线拟合是将一个轮廓近似表示为一条与该轮廓形状相近的直线。

直线拟合可以用于以下几个方面:

  • 形状识别:通过直线拟合可以提取图像中物体的轮廓特征,这些特征可以用于物体识别。例如,可以通过拟合直线来识别图像中的道路、边缘等。

  • 目标跟踪:通过直线拟合可以对目标的运动进行跟踪。例如,可以通过拟合直线来跟踪图像中的车辆、飞机等。

  • 图像分割:通过直线拟合可以将图像分割成不同的区域。例如,可以通过拟合直线来分割图像中的文字、图形等。

直线拟合有以下几种常用方法:

  • 最小二乘法:最小二乘法是基于最小化拟合误差的思想,通过迭代的方法求解直线参数。该方法的优点是简单易实现,缺点是计算量大,当轮廓点数较多时,容易出现收敛问题。

  • 最小距离法:最小距离法是基于最小化样本点到直线的距离的思想,通过迭代的方法求解直线参数。该方法的优点是计算量小,收敛速度快,缺点是对初始值敏感。

  • 基于图像特征的方法:基于图像特征的方法是利用图像特征来拟合直线。常用的图像特征包括边缘点、极值点、角点等。该方法的优点是鲁棒性强,缺点是计算量大。

在 OpenCV 提供了 fitLine() 函数实现直线拟合。

void fitLine( InputArray points, OutputArray line, int distType,
                           double param, double reps, double aeps );

第一个参数 points:表示输入点集,可以是 Point 数组或 Mat 矩阵。第二个参数 line:输出直线。

  • 对于二维直线而言类型为 Vec4f,包含 (vx, vy, x0, y0),其中(vx, vy) 表示直线的方向,(x0, y0) 表示直线上的一点。

  • 对于三维直线类型则是 Vec6f,包含 (vx, vy, vz, x0, y0, z0),其中(vx, vy, vz) 表示直线的方向,(x0, y0, z0) 表示直线上的一点。

第三个参数 distType:表示距离类型,也就是在直线拟合时使用哪种算法。这里的算法基于 M-estimators 实现:

  • DIST_L1:

  • DIST_L2:

  • DIST_C

  • DIST_L12:

  • DIST_FAIR: ,C=1.3998

  • DIST_WELSCH: ,C=2.9846

  • DIST_HUBER: ,C=1.345

第四个参数 param:表示距离参数,跟所选的距离类型有关。如果为 0,则自动选择最佳值。第五个参数 reps:表示拟合直线所需要的径向精度,通常该值被设定为 0.01。第六个参数 aeps:表示拟合直线所需要的角度精度,通常该值被设定为 0.01。

下面的例子,将一些点拟合成一条直线,并找到直线的极值点。

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main(int argc, char **argv) {
    Mat image(800, 800, CV_8UC3, Scalar(0,0,0));

    vector<Point> points;
    points.push_back(Point(48, 58));
    points.push_back(Point(105, 98));
    points.push_back(Point(155, 160));
    points.push_back(Point(212, 220));
    points.push_back(Point(248, 260));
    points.push_back(Point(320, 300));
    points.push_back(Point(350, 360));
    points.push_back(Point(412, 400));

    //将拟合点绘制到空白图上
    for (int i = 0; i < points.size(); i++)
    {
        circle(image, points[i], 5, cv::Scalar(0, 0, 255), 2, 8);
    }
    imshow("src", image);

    cv::Vec4f line_para;
    cv::fitLine(points, line_para, cv::DIST_L2, 0, 1e-2, 1e-2);
    std::cout << "line_para = " << line_para << std::endl;

    //获取直线的斜率、截矩
    float vx = line_para[0];
    float vy = line_para[1];
    float x0 = line_para[2];
    float y0 = line_para[3];

    float k = vy / vx;
    float b = y0 - k*x0;

    // 寻找直线的极值点
    int minx = 0, miny = 10000;
    int maxx = 0, maxy = 0;
    for (int i = 0; i < points.size(); i++) {
        Point pt = points[i];
        if (miny > pt.y) {
            miny = pt.y;
        }
        if (maxy < pt.y) {
            maxy = pt.y;
        }
    }
    maxx = (maxy - b) / k;
    minx = (miny - b) / k;
    line(image, Point(maxx, maxy), Point(minx, miny), Scalar(255, 0, 0), 2, 8);

    imshow("result", image);
    waitKey(0);

    return 0;
}
OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合,opencv,笔记,人工智能,计算机视觉
点的直线拟合.png

下面的例子,对轮廓进行直线拟合。

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace std;
using namespace cv;

bool ascendSort(vector<Point> a,vector<Point> b)
{
    return contourArea(a) > contourArea(b);
}

int main(int argc, char **argv) {
    Mat src = imread(".../test.jpg");
    imshow("src", src);

    Mat gray,thresh;
    cvtColor(src, gray, cv::COLOR_BGR2GRAY);

    threshold(gray,thresh,0,255,THRESH_BINARY_INV | THRESH_OTSU);
    imshow("thresh", thresh);

    vector<vector<Point>> contours;
    vector<Vec4i> hierarchy;
    findContours(thresh, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
    sort(contours.begin(), contours.end(), ascendSort);//ascending sort

    for (size_t t = 0; t< contours.size(); t++) {
        double area = contourArea(contours[t]);

        if (area < 1000) {
            continue;
        }

        // 直线拟合
        Vec4f line_para;
        fitLine(contours[t], line_para, DIST_L2, 0, 0.01, 0.01);
        //获取直线的斜率、截矩
        float vx = line_para[0];
        float vy = line_para[1];
        float x0 = line_para[2];
        float y0 = line_para[3];

        float k = vy / vx;
        float b = y0 - k*x0;

        // 寻找直线的极值点
        int minx = 0, miny = 10000;
        int maxx = 0, maxy = 0;
        for (int i = 0; i < contours[t].size(); i++) {
            Point pt = contours[t][i];
            if (miny > pt.y) {
                miny = pt.y;
            }
            if (maxy < pt.y) {
                maxy = pt.y;
            }
        }
        maxx = (maxy - b) / k;
        minx = (miny - b) / k;
        line(src, Point(maxx, maxy), Point(minx, miny), Scalar(255, 0, 0), 8, 8);
    }
    imshow("result", src);

    waitKey(0);
    return 0;
}
OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合,opencv,笔记,人工智能,计算机视觉
轮廓的直线拟合.png

3.  总结

本文介绍了在 OpenCV 中如何对轮廓进行椭圆拟合和直线拟合。它们可以用于提取轮廓的特征,简化轮廓的表示,提高轮廓的处理效率。它们在图像分割、目标识别、目标跟踪等任务中有着广泛的应用。

Java与Android技术栈】公众号

关注 Java/Kotlin 服务端、桌面端 、Android 、机器学习、端侧智能

更多精彩内容请关注:文章来源地址https://www.toymoban.com/news/detail-805405.html

到了这里,关于OpenCV 笔记(17):轮廓的椭圆拟合、直线拟合的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • OpenCV(十三):图像中绘制直线、圆形、椭圆形、矩形、多边形和文字

    目录 1.绘制直线line() 2.绘制圆形circle() 3.绘制椭圆形ellipse()  4.绘制矩形rectangle() 5.绘制多边形 fillPoly()  6.绘制文字putText() 7.例子 1.绘制直线line() img:绘制圆形的图像 ptl:直线起始点在图像中的坐标 pt2: 直线终点在图像中的坐标 color:圆形的颜色,用三通道表示 thickness:轮廓的宽

    2024年02月09日
    浏览(41)
  • OpenCV(三十七):拟合直线、三角形和圆形

    1.点集拟合的含义        点集拟合是一种通过拟合函数或曲线来近似描述给定离散数据点的技术,在点集拟合中,可以使用不同的函数或曲线拟合方法来拟合直线、三角形和圆形。 直线拟合 :对于给定的二维数据点集合,可以使用最小二乘法来拟合一条直线。 三角形拟合

    2024年02月03日
    浏览(41)
  • 【OpenCV-Python】——边缘和轮廓&Laplacian/Sobel/Canny边缘检测&查找/绘制轮廓及轮廓特征&霍夫直线/圆变换

    目录 前言: 1、边缘检测 1.1 Laplacian边缘检测  1.2 Sobel边缘检测  1.3 Canny边缘检测 2、图像轮廓 2.1 查找轮廓  2.2 绘制轮廓 2.3 轮廓特征 3、霍夫变换 3.1 霍夫直线变换  3.2 霍夫圆变换 总结: 图像的边缘是指图像中灰度值急剧变化的位置,边缘检测的目的是为了绘制边缘线条。

    2024年01月23日
    浏览(39)
  • OpenCV快速入门:目标检测——轮廓检测、轮廓的距、点集拟合和二维码检测

    在当今数字化时代,计算机视觉的崛起使得目标检测成为科技领域中的一项关键技术。本文将带您快速入门OpenCV中的目标检测,深入探讨轮廓检测、轮廓的距、点集拟合以及二维码检测等核心概念。 OpenCV,作为一种强大的开源计算机视觉库,为开发者提供了丰富的工具和算法

    2024年01月16日
    浏览(41)
  • OpenCV(10): 轮廓近似—多边形拟合,边界矩形与边界圆形

    轮廓近似(Contour Approximation)是指对轮廓进行逼近或拟合,得到近似的轮廓。在图像处理中,轮廓表示了图像中物体的边界,因此轮廓近似可以用来描述和识别物体的形状。 多边形拟合(Approximating Polygons)是将轮廓逼近成一个由直线段构成的多边形。常见的有最小包围矩形

    2024年02月10日
    浏览(31)
  • Opencv之RANSAC算法用于直线拟合及特征点集匹配详解

    讲述Ransac拟合与最小二乘在曲线拟合上的优缺点 讲述在进行特征点匹配时,最近邻匹配与Ransac匹配的不同之处 另外,Ransac也被用于椭圆拟合、变换矩阵求解等 1.1 原理 RANSAC(RANdom SAmple Consensus,随机采样一致)算法是从一组含有“外点”(outliers)的数据中正确估计数学模型参数的

    2024年02月05日
    浏览(29)
  • 利用OpenCV与Qt5构建卡尺拟合直线工具(C++实现)

    基于OpenCV与Qt5构建卡尺拟合直线工具 博主近期基于海康Vision Master4.0做了一个工业视觉工程项目,其中就使用到了海康VM的找直线工具,然后博主根据其中的技术原理,也仿照开发了一个类似的功能,基于OpenCV和Qt5构建一个卡尺找直线的工具。卡尺找直线是在计算机视觉领域中

    2024年02月08日
    浏览(36)
  • opencv--轮廓拟合函数 boundingRect(),minAreaRect(),minEnclosingCircle(),fitEllipse(),fitLine()

    目录 1.cv2.boundingRect() 2.cv2.minAreaRect() 3. cv2.minEnclosingCircle() 4.cv2.fitEllipse()  5.cv2.fitLine()   在计算轮廓时,可能并不需要实际的轮廓,而仅需要一个接近于轮廓的近似多边形。OpenCV提供了多种计算轮廓近似多边形的方法。 能够返回包围轮廓的矩形的边界信息。 函数样式: retv

    2024年02月16日
    浏览(26)
  • OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合

    目录 1.轮廓外接最大矩形boundingRect() 2.轮廓外接最小矩形minAreaRect() 3.轮廓外接多边形approxPolyDP() 1.轮廓外接最大矩形boundingRect() Rect cv::boundingRect ( InputArray array ) array:输入的灰度图像或者2D点集,数据类型为vectorPoint或者Mat。 示例代码:  轮廓外接最大矩形的结果: 2.轮廓外接

    2024年02月09日
    浏览(27)
  • C++opencv找圆心?看着一篇,一定有你要(边缘轮廓检测,拟合,凸包)找出相应的轮廓或者全部轮廓画外界圆轮廓并且标出轮廓中心

    注意这种面积筛选有一个弊端就是比如有两个轮廓, A轮廓为500 B轮廓为300 当面积设置为 area400时就可以筛选出面积小于300的所有轮廓 反之大于300的轮廓 如果有两个圆轮廓一大一小,可能就只能保留一个了 如果知道这两个形状的轮廓面积,或许可以利用 逻辑与  进行筛选。

    2024年02月11日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包