OpenCV结构分析与形状描述符(13)拟合椭圆函数fitEllipseDirect()的使用

  • 操作系统:ubuntu22.04
  • OpenCV版本:OpenCV4.9
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

围绕一组2D点拟合一个椭圆。
该函数计算出一个椭圆,该椭圆拟合一组2D点。它返回一个内切于该椭圆的旋转矩形。使用了由[91]提出的直接最小二乘法(Direct)方法。

对于椭圆,这个基集是 χ = ( x 2 , x y , y 2 , x , y , 1 ) \chi= \left(x^2, x y, y^2, x, y, 1\right) χ=(x2,xy,y2,x,y,1),这是一个包含六个自由系数的集合 A T = { A xx , A xy , A yy , A x , A y , A 0 } A^T=\left\{A_{\text{xx}},A_{\text{xy}},A_{\text{yy}},A_x,A_y,A_0\right\} AT={Axx,Axy,Ayy,Ax,Ay,A0}然而,要指定一个椭圆,只需要五个数字;主轴和次轴的长度 ( a , b ) (a,b) (a,b),位置 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),以及方向 θ。这是因为空间中还包含了直线、二次函数、抛物线和双曲线函数作为可能的拟合。直接方法通过确保 4 A x x A y y − A x y 2 > 0 4 A_{xx} A_{yy}- A_{xy}^2 > 0 4AxxAyyAxy2>0来将拟合限定为椭圆。施加的条件是 4 A x x A y y − A x y 2 = 1 4 A_{xx} A_{yy}- A_{xy}^2=1 4AxxAyyAxy2=1,这满足了不等式,并且由于系数可以任意缩放,因此这一条件并不过于限制

ϵ 2 = A T D T D A 其中 A T C A = 1 并且 C = ( 0 0 2 0 0 0 0 − 1 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ) \begin{equation*} \epsilon ^2= A^T D^T D A \quad \text{其中} \quad A^T C A =1 \quad \text{并且} \quad C=\left(\begin{matrix} 0 & 0 & 2 & 0 & 0 & 0 \\ 0 & -1 & 0 & 0 & 0 & 0 \\ 2 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 \end{matrix} \right) \end{equation*} ϵ2=ATDTDA其中ATCA=1并且C= 002000010000200000000000000000000000

最小成本是通过求解广义特征值问题找到的。
D T D A = λ ( C ) A \begin{equation*} D^T D A = \lambda \left( C\right) A \end{equation*} DTDA=λ(C)A
系统只产生一个正的特征值 λ,该特征值被选作解,并且其特征向量u也被选出。这些值用来找到系数
A = 1 u T C u u \begin{equation*} A = \sqrt{\frac{1}{\mathbf{u}^T C \mathbf{u}}} \mathbf{u} \end{equation*} A=uTCu1 u
缩放因子保证了 A T C A = 1 A^T C A =1 ATCA=1

fitEllipseDirect 是 OpenCV 中用于拟合椭圆的一个函数,它使用了直接线性最小二乘法(Direct Least Squares Fit)来进行椭圆拟合。这种方法通常比其他方法更快,但也可能在某些情况下不如其他方法稳健。

函数原型


RotatedRect cv::fitEllipseDirect
(
	InputArray 	points
)	

参数

  • 参数points 输入的2D点集,存储在 std::vector<> 或 Mat 中。

代码示例


#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main()
{
    // 创建一个空白图像
    Mat img( 400, 400, CV_8UC3, Scalar( 255, 255, 255 ) );

    // 创建一组2D点
    vector< Point2f > points;
    points.push_back( Point2f( 100, 100 ) );
    points.push_back( Point2f( 200, 100 ) );
    points.push_back( Point2f( 200, 200 ) );
    points.push_back( Point2f( 100, 200 ) );
    points.push_back( Point2f( 150, 150 ) );
    points.push_back( Point2f( 150, 250 ) );
    points.push_back( Point2f( 250, 150 ) );
    points.push_back( Point2f( 250, 250 ) );

    // 拟合椭圆
    RotatedRect ellipse = fitEllipseDirect( points );

    // 获取椭圆的四个顶点
    vector< Point2f > boxPoints;
    boxPoints.resize( 4 );  // 确保boxPoints至少有4个元素
    ellipse.points( boxPoints.data() );

    // 将 Point2f 转换为 Point
    vector< Point > intBoxPoints;
    for ( const auto& pt : boxPoints )
    {
        intBoxPoints.push_back( Point( static_cast< int >( pt.x ), static_cast< int >( pt.y ) ) );
    }

    // 在原图上绘制椭圆
    polylines( img, intBoxPoints, true, Scalar( 0, 0, 255 ), 2, LINE_8 );

    // 绘制点集
    for ( const auto& pt : points )
    {
        circle( img, pt, 5, Scalar( 0, 255, 0 ), -1 );
    }

    // 显示结果
    imshow( "Ellipse Fitting (Direct)", img );
    waitKey( 0 );

    return 0;
}

运行结果

在这里插入图片描述

  • 21
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值