OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆

这篇具有很好参考价值的文章主要介绍了OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

FitEllipse椭圆拟合

函数说明:基于最小二乘法(least-squares sense)计算围绕一组(个数大于等于5个)给定的点集拟合一个椭圆。返回该椭圆的最小外接矩形(如果给定的点是在一条直线上,该矩形的最小边为0)。注意返回的数值可能有负数(大边界之外)。

//函数原型1
RotatedRect FitEllipse(InputArray points)

//函数原型2
RotatedRect FitEllipse(IEnumerable<Point> points)

//函数原型3
RotatedRect FitEllipse(IEnumerable<Point2f> points)

参数

说明

InputArray points

IEnumerable<Point> points

IEnumerable<Point2f> points

待拟合椭圆的点集,个数大于等于5个。

返回值RotatedRect

拟合的椭圆的最小外接矩形,点在一直线上的话,该矩形最小边为0

FitEllipseAMS椭圆拟合(Approximate Mean Square(AMS))

函数说明:基于Approximate Mean Square(近似均方) 方法计算点集的拟合椭圆

//函数原型1
RotatedRect FitEllipseAMS(InputArray points)

//函数原型2
RotatedRect FitEllipseAMS(IEnumerable<Point> points)

//函数原型3
RotatedRect FitEllipseAMS(IEnumerable<Point2f> points)

FitEllipseDirect椭圆拟合(Direct least square(Direct))

函数说明:基于Direct least square(最小二乘法) 方法计算点集的拟合椭圆

//函数原型1
RotatedRect FitEllipseDirect(InputArray points)

//函数原型2
RotatedRect FitEllipseDirect(IEnumerable<Point> points)

//函数原型3
RotatedRect FitEllipseDirect(IEnumerable<Point2f> points)

三个函数对比

FitEllipse:据说是,速度快些,但结果不一定是最佳的(如图像示例中的大蓝色框)

FitEllipseAMS:速度慢些,但结果更优。

AMS和Direct算法看不懂,有能讲明白的高人或简明的参考的链接,望评论区被补上,感谢。

MinEnclosingCircle最小外接圆

函数说明:获取一组坐标点集的最小外接圆,返回中心点和半径。

//函数原型1
void MinEnclosingCircle(InputArray points,
    out Point2f center,
    out float radius)

//函数原型2
void MinEnclosingCircle(IEnumerable<Point> points,
    out Point2f center,
    out float radius) 

//函数原型3
void MinEnclosingCircle(IEnumerable<Point2f> points,
    out Point2f center,
    out float radius)

参数

说明

InputArray points

IEnumerable<Point> points

IEnumerable<Point2f> points

待计算最小外接圆的点集。数据类型必须为CV_32SC2 或CV_32FC2

out Point2f center

输出最小外接圆的中心点

out float radius

输出最小外接圆的半径

图像示例

原图

OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆,OpenCvSharp函数,opencv,图像处理,c#,Powered by 金山文档

示例

OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆,OpenCvSharp函数,opencv,图像处理,c#,Powered by 金山文档

源码示例

private string winName = "FitEllipse";        
private Mat image = new Mat();

private bool fitEllipseQ = true;
private bool fitEllipseAMSQ = true;
private bool fitEllipseDirectQ = true;
private bool minEnclosingCircleColorQ = true;

Scalar minEnclosingCircleColor = new Scalar(255, 255, 0);
Scalar fitEllipseColor = new Scalar(255, 0, 0);
Scalar fitEllipseAMSColor = new Scalar(0, 255, 0);
Scalar fitEllipseDirectColor = new Scalar(0, 0, 255);
Scalar fitEllipseTrueColor = new Scalar(255, 255, 255);

public void Run(ParamBase paramBase) {

    image = Cv2.ImRead(ImagePath.Ellipses, ImreadModes.Grayscale);
    if (image.Empty()) throw new Exception($"图像打开有误:{ImagePath.Ellipses}");
    Cv2.ImShow("source", image);
    Cv2.NamedWindow(winName, WindowFlags.Normal);
    Cv2.ResizeWindow(winName, image.Width * 2,image.Height*2);
    Cv2.CreateTrackbar("threshold", winName, 255, ProcessImage);
    Cv2.SetTrackbarPos("threshold", winName, 102);
    //ProcessImage(0, IntPtr.Zero);
    while (true) {
        if (Cv2.WaitKey(50) == (int)Keys.Escape) break;
    }
    Cv2.DestroyAllWindows();
    image.Dispose();

}

private void ProcessImage(int pos, IntPtr userData) {
    RotatedRect box = new RotatedRect();
    RotatedRect boxAMS = new RotatedRect();
    RotatedRect boxDirect = new RotatedRect();

    using Mat bImage = image.GreaterThanOrEqual(pos);

    //轮廓发现
    Point[][] contours = Cv2.FindContoursAsArray(bImage, RetrievalModes.List, ContourApproximationModes.ApproxNone);

    Canvas paper = new Canvas();
    paper.Init((int)(0.8 * Math.Min(bImage.Rows, bImage.Cols)), (int)(1.2 * Math.Max(bImage.Rows, bImage.Cols)));
    paper.Stretch(new Point2f(0.0f, 0.0f), new Point2f((float)(bImage.Cols + 2.0), (float)(bImage.Rows + 2.0)));

    List<string> text = new List<string>();
    List<Scalar> color = new List<Scalar>();

    if (minEnclosingCircleColorQ) {
        text.Add("minEnclosingCircle");
        color.Add(minEnclosingCircleColor);
    }

    if (fitEllipseQ) {
        text.Add("OpenCV");
        color.Add(fitEllipseColor);
    }
    if (fitEllipseAMSQ) {
        text.Add("AMS");
        color.Add(fitEllipseAMSColor);
    }
    if (fitEllipseDirectQ) {
        text.Add("Direct");
        color.Add(fitEllipseDirectColor);
    }
    paper.DrawLabels(text.ToArray(), color.ToArray());

    int margin = 2;
    List<List<Point>> points = new List<List<Point>>();
    for (int i = 0; i < contours.Length; i++) {
        int count = contours[i].Length;
        //椭圆拟合至少要5个坐标点
        if (count < 6) continue;
        List<Point> pts = new List<Point>();
        for (int j = 0; j < count; j++) {
            Point pnt = contours[i][j];
            if ((pnt.X > margin && pnt.Y > margin && pnt.X < bImage.Cols - margin && pnt.Y < bImage.Rows - margin)) {
                if (j % 20 == 0) {
                    pts.Add(pnt);
                }
            }
        }
        points.Add(pts);
    }

    //直线的话,FitEllipse返回的最小外接矩形的width为0
    //points.Clear();
    //points.Add(new List<Point>() { new Point(0, 50), new Point(0, 100), new Point(0, 150), new Point(0, 200), new Point(0, 250) });

    //为一个点的话,FitEllipse返回的最小外接矩形的Width和Height都为0
    //points.Clear();
    //points.Add(new List<Point>() { new Point(100, 50), new Point(100, 50), new Point(100, 50), new Point(100, 50), new Point(100, 50) });

    for (int i = 0; i < points.Count(); i++) {
        var pts = points[i];
        //最少5个点
        if (pts.Count() < 5) {
            continue;
        }
        var ptfs = pts.ConvertAll(z => new Point2f(z.X, z.Y));
        bool drawPoint = false;


        if (fitEllipseQ) {
            box = Cv2.FitEllipse(ptfs);
            if (box.Size.Height <= box.Size.Width * 30 &&
                box.Size.Width > 0) {//如果是一条直线或同一点时,Width=0
                paper.DrawEllipseWithBox(box, fitEllipseColor, 3);
                drawPoint = true;
            }
        }
        if (fitEllipseAMSQ) {
            boxAMS = Cv2.FitEllipseAMS(ptfs);
            if (boxAMS.Size.Height <= boxAMS.Size.Width * 30 &&
                boxAMS.Size.Width > 0) {
                paper.DrawEllipseWithBox(boxAMS, fitEllipseAMSColor, 2);
                drawPoint = true;
            }
        }
        if (fitEllipseDirectQ) {
            boxDirect = Cv2.FitEllipseDirect(ptfs);
            if (boxDirect.Size.Height <= boxDirect.Size.Width * 30 &&
                boxDirect.Size.Width > 0) {
                paper.DrawEllipseWithBox(boxDirect, fitEllipseDirectColor, 1);
                drawPoint = true;
            }
        }
        if (!drawPoint) continue;
        if (minEnclosingCircleColorQ) {
            //最小外接圆
            Cv2.MinEnclosingCircle(ptfs, out Point2f center, out float radius);
            paper.DrawCircle(center, radius, minEnclosingCircleColor, 1);
            drawPoint = true;
        }
        paper.DrawPoints(ptfs.ToArray(), fitEllipseTrueColor);
    }

    Cv2.ImShow(winName, paper.img);
    paper.Dispose();
}

internal class Canvas : IDisposable {
    public bool setupQ { get; set; }
    public Point origin { get; set; }
    public Point corner { get; set; }
    public int minDims { get; set; }
    public int maxDims { get; set; }
    public double scale { get; set; }
    public int rows { get; set; }
    public int cols { get; set; }

    public Mat img { get; set; } = new Mat();
    public void Init(int minD, int maxD) {
        // Initialise the canvas with minimum and maximum rows and column sizes.
        minDims = minD; maxDims = maxD;
        origin = new Point(0, 0);
        corner = new Point(0, 0);
        scale = 1.0;
        rows = 0;
        cols = 0;
        setupQ = false;
    }

    public void Stretch(Point2f min, Point2f max) {
        // Stretch the canvas to include the points min and max.
        if (setupQ) {
            if (corner.X < max.X) { corner = new Point((int)(max.X + 1.0), corner.Y); };
            if (corner.Y < max.Y) { corner = new Point(corner.X, (int)(max.Y + 1.0)); };
            if (origin.X > min.X) { origin = new Point((int)min.X, origin.Y); };
            if (origin.Y > min.Y) { origin = new Point(origin.X, (int)min.Y); };
        }
        else {
            origin = new Point((int)min.X, (int)min.Y);
            corner = new Point((int)(max.X + 1.0), (int)(max.Y + 1.0));
        }
        int c = (int)(scale * ((corner.X + 1.0) - origin.X));
        if (c < minDims) {
            scale = scale * (double)minDims / (double)c;
        }
        else {
            if (c > maxDims) {
                scale = scale * (double)maxDims / (double)c;
            }
        }
        int r = (int)(scale * ((corner.Y + 1.0) - origin.Y));
        if (r < minDims) {
            scale = scale * (double)minDims / (double)r;
        }
        else {
            if (r > maxDims) {
                scale = scale * (double)maxDims / (double)r;
            }
        }
        cols = (int)(scale * ((corner.X + 1.0) - origin.X));
        rows = (int)(scale * ((corner.Y + 1.0) - origin.Y));
        setupQ = true;
    }

    public void Stretch(Point2f[] pts) {
        // Stretch the canvas so all the points pts are on the canvas.
        Point2f min = pts[0];
        Point2f max = pts[0];
        for (int i = 1; i < pts.Length; i++) {
            Point2f pnt = pts[i];
            if (max.X < pnt.X) { max.X = pnt.X; };
            if (max.Y < pnt.Y) { max.Y = pnt.Y; };
            if (min.X > pnt.X) { min.X = pnt.X; };
            if (min.Y > pnt.Y) { min.Y = pnt.Y; };
        };
        Stretch(min, max);
    }

    public void Stretch(RotatedRect box) {   // Stretch the canvas so that the rectangle box is on the canvas.
        Point2f min = box.Center;
        Point2f max = box.Center;
        Point2f[] vtx = box.Points();
        for (int i = 0; i < 4; i++) {
            Point2f pnt = vtx[i];
            if (max.X < pnt.X) { max.X = pnt.X; };
            if (max.Y < pnt.Y) { max.Y = pnt.Y; };
            if (min.X > pnt.X) { min.X = pnt.X; };
            if (min.Y > pnt.Y) { min.Y = pnt.Y; };
        }
        Stretch(min, max);
    }

    private Point ToPoint(Point2f point2f) {
        //注意OpenCV的Point2f转Point的是使用 template<> inline int saturate_cast<int>(float v)            { return cvRound(v); }
        //而OpenCvSharpe的point2f.ToPoint();是向下取整
        return new Point(Math.Round(point2f.X), Math.Round(point2f.Y));
    }

    public void DrawEllipseWithBox(RotatedRect box, Scalar color, int lineThickness) {
        if (img.Empty()) {
            Stretch(box);
            img = Mat.Zeros(rows, cols, MatType.CV_8UC3);
        }
        box.Center = new Point2f(box.Center.X - origin.X, box.Center.Y - origin.Y) * scale;
        box.Size.Width = (float)(scale * box.Size.Width);
        box.Size.Height = (float)(scale * box.Size.Height);
        Cv2.Ellipse(img, box, color, lineThickness, LineTypes.AntiAlias);
        Point2f[] vtx = box.Points();
        for (int j = 0; j < 4; j++) {
            Cv2.Line(img, ToPoint(vtx[j]), ToPoint(vtx[(j + 1) % 4]), color, lineThickness, LineTypes.AntiAlias);
        }
    }
    public void DrawCircle(Point2f center,float radius, Scalar color, int lineThickness) {
        var Center = new Point2f(center.X - origin.X, center.Y - origin.Y) * scale;

        Cv2.Circle(img, (int)((center.X - origin.X) * scale), (int)((center.Y - origin.Y) * scale), (int)(radius * scale), color, lineThickness);
    }
    public void DrawPoints(Point2f[] pts, Scalar color) {
        if (img.Empty()) {
            Stretch(pts);
            img = Mat.Zeros(rows, cols, MatType.CV_8UC3);
        }
        for (int i = 0; i < pts.Length; i++) {
            Point pnt = new Point(pts[i].X - origin.X, pts[i].Y - origin.Y) * scale;
            img.At<Vec3b>(pnt.Y, pnt.X) = color.ToVec3b();
        }
    }
    public void DrawLabels(string[] texts, Scalar[] colors) {
        if (img.Empty()) {
            img = Mat.Zeros(rows, cols, MatType.CV_8UC3);
        }
        int vPos = 0;
        for (int i = 0; i < texts.Length; i++) {
            Size textsize = Cv2.GetTextSize(texts[i], HersheyFonts.HersheyComplex, 1, 1, out int baseLine);
            vPos += (int)(textsize.Height * 1.3);
            Point org = new Point((img.Cols - textsize.Width), vPos);
            Cv2.PutText(img, texts[i], org, HersheyFonts.HersheyComplex, 1, colors[i], 1, LineTypes.Link8);
        }            
    }

    public void Dispose() {
        if (img != null) { img.Dispose(); }
        img = null;
    }
}

官网C++源码https://github.com/opencv/opencv/blob/4.x/samples/cpp/fitellipse.cpp

官网源码有一点点笔误小BUG,前一个PR还没处理完呢,这个PR不知如何操作(Git好用,难学呀)

避坑,Point2f转Point

还有,C++版的line可以传point2f(通过saturate_cast装饰float转int是四舍五入)画线,而OpenCvSharp的Line需要将Point2f转Point(通过ToPoint()的话,是直接取整)

template<> inline int saturate_cast<int>(float v)            { return cvRound(v); }
public readonly Point ToPoint() {
            return new Point((int)X, (int)Y);
        }

OpenCvSharp函数示例(目录)

参考

https://docs.opencv.org/文章来源地址https://www.toymoban.com/news/detail-695379.html

到了这里,关于OpenCvSharp函数:FitEllipse/FitEllipseAMS/FitEllipseDirect椭圆拟合、MinEnclosingCircle最小外接圆的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • C#基于OpenCv(OpenCvSharp) 的 fftshift, ifftshift 函数的实现

    本文实现基于 OpenCv ( OpenCvSharp ) 的 fftshift, ifftshift 函数。 fftshift 函数将信号频谱的零频分量移动到数组中心, 本质是分别对调一三象限数据。 ifftshift完成相反的操作,本质是二四象限的数据块。 OpenCV中没有这两个函数如果使用需要自己实现。 实现代码如下:

    2024年02月14日
    浏览(29)
  • C#使用OpenCvSharp4库中5个基础函数-灰度化、高斯模糊、Canny边缘检测、膨胀、腐蚀

    使用OpenCV可以对彩色原始图像进行基本的处理,涉及到5个常用的处理: 灰度化 模糊处理 Canny边缘检测 膨胀 腐蚀 本例中我们采用数字图像处理中经常用到的一副标准图像 lena.png 作为测试图像,如下图所示: 具体资源下载地址为:lena图像下载地址 首先我们新建一个基于C# .

    2024年04月22日
    浏览(41)
  • 《数字图像处理-OpenCV/Python》连载(26)绘制椭圆和椭圆弧

    本书京东优惠购书链接:https://item.jd.com/14098452.html 本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html 本章介绍OpenCV的绘图功能和简单的鼠标交互处理方法。与Excel或Matplotlib中的可视化数据图不同,OpenCV中的绘图功能主要用于在图像的指定位置绘制几何图形。 本

    2024年02月06日
    浏览(48)
  • C#图像处理-OpenCVSharp教程:OpenCVSharp与EmguCV的比较与介绍

    C#图像处理-OpenCVSharp教程:OpenCVSharp与EmguCV的比较与介绍 图像处理在计算机视觉和计算机图形学等领域发挥着至关重要的作用。本教程将介绍在C#中使用OpenCVSharp和EmguCV这两个流行的图像处理库,它们提供了丰富的功能和强大的性能。 一、OpenCVSharp介绍与特点 OpenCVSharp是OpenCV的

    2024年02月21日
    浏览(28)
  • 高质量椭圆检测库

    目录 前言 效果展示 检测库 简介 安装库 用法 测试 论文算法步骤简读 1. lsd 检测 2. lsd group 3. 生成初始 ellipse 4. 聚类 椭圆检测是工业中比较常用的一种检测需求。目前常用的基于传统图像处理的椭圆检测方法是霍夫变换,但是霍变换的检测率比较低,很难满足工业场景。而基

    2024年02月07日
    浏览(39)
  • ECC椭圆曲线入门

    https://web3study.club/ ECC(Ellipse Curve Cryptography)又称椭圆曲线密码体制、椭圆曲线加密算法等。 椭圆曲线加密算法在比特币、区块链上有着广泛的应用。 公式: y^2 = x^3 + ax + b 这里使用简单易懂的方式对大家介绍这部分内容,让大家有个简单的理解 公私钥加密内容​ 公钥未公开部

    2023年04月09日
    浏览(31)
  • 常用椭圆曲线介绍

    chat-gpt生成,对应python的miracl/core/python库 ED系列 一、ED25519 ED25519使用的椭圆曲线是Curve25519,它是一种高效且安全的椭圆曲线,由Daniel J. Bernstein等人设计。 ED25519的 密钥长度为256位,提供了128位的安全性。 ED25519可以用于生成密钥对、进行数字签名和验证签名。 由于其高效性

    2024年02月14日
    浏览(32)
  • 椭圆曲线加密原理与应用

    由于RSA、AES等国际算法面临高强度算法禁售和被部署后门风险,我国基于ECC椭圆曲线,自研SM2/SM3/SM4/SM9一套安全算法。根据国家整体战略,金融及重要领域要逐步实现国密算法替换,另根据人民银行总体规划,在2022年金融行业要全面应用国密算法。 在FireFly移动金融开发平台

    2024年02月05日
    浏览(35)
  • MATLAB--椭圆拟合算法

    This code aims for ellipse fitting but only contains the center’s calculation. 使用: xcell为x坐标数组,ycell为y坐标数组;

    2024年04月17日
    浏览(31)
  • MATLAB—绘制椭圆

    绘制圆,变换成椭圆(这里需要一个变换矩阵)。 MATLAB中的绘制:使用参数方程的形式。 figure(1) plot([-5 5],[0 0],\\\'k\\\',\\\'LineWidth\\\',1);hold on;% 画坐标轴 plot([0 0],[-5 5],\\\'k\\\',\\\'LineWidth\\\',1);hold on; theta=0:pi/20:2*pi;% 参数theta a=2;b=3;% 长短轴 x1=a*cos(theta) +1;% 偏置 y1=b*sin(theta) +1; plot(x1,y1,\\\'-\\\');hold on;

    2024年02月07日
    浏览(34)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包