使用OpenCV的函数minEllipse()求轮廓的外接椭圆时一定要判断构成轮廓的点个数是否大于5个

本文介绍使用OpenCV的minEllipse()函数求轮廓外接椭圆时的注意事项,特别是对于轮廓点数量的要求。如果轮廓点少于5个,将会引发错误。文中提供了一段示例代码来展示如何正确地应用此函数。

使用OpenCV的函数minEllipse()求轮廓的外接椭圆时一定要判断构成轮廓的点个数是否大于5个,如果不判断,是要报错的,如下图所示

OpenCV Error: Incorrect size of input array (There should be at least 5 points to fit the ellipse) in cv::fitEllipse, file C:\builds\master_PackSlave-win32-vc11-shared\opencv\modules\imgproc\src\shapedescr.cpp, line 379

正确的示例代码如下

 // 求轮廓的外接椭圆  
        if (contours[i].size() > 5) //使用前一定要判断是否大于5个点,小于5个点要报错  
        {  
            minEllipse[i] = fitEllipse(Mat(contours[i]));  
        }  
<think>我们面对的问题是如何从`fitEllipse`函数返回的`vector<cv::RotatedRect>`对象中获取每个椭圆外接矩形。在OpenCV中,`cv::fitEllipse`函数返回的是一个`cv::RotatedRect`对象(即使输入是轮廓向量,它也会为每个轮廓拟合一个椭圆,并返回一个`RotatedRect`向量)。`cv::RotatedRect`表示一个旋转矩形,它恰好是拟合椭圆外接矩形(注意:这个外接矩形是旋转的,即最小外接矩形)。但是请注意:`cv::RotatedRect`本身就是一个外接矩形(旋转矩形),它已经包含了椭圆外接矩形信息。所以,我们不需要再额外计算,因为`fitEllipse`返回的`RotatedRect`就是椭圆外接矩形(最小外接矩形)。然而,有候我们可能需要非旋转的(轴对齐的)外接矩形。在这种情况下,我们可以使用`cv::RotatedRect`的`boundingRect()`成员函数(注意:实际上`cv::RotatedRect`类并没有`boundingRect`成员函数,所以我们需要用其他方法)。实际上,OpenCV提供了两种外接矩形:1.最小外接矩形(旋转矩形)-由`cv::fitEllipse`返回的`RotatedRect`对象表示。2.轴对齐的外接矩形(非旋转)-我们可以通过`cv::boundingRect`函数计算得到,但是这个函数需要输入集。因此,如果我们想要得到椭圆轴对齐的外接矩形,我们需要:1.从`RotatedRect`中获取椭圆的边界(通常取4个顶)。2.然后对这些调用`cv::boundingRect`来得到轴对齐的矩形。但是,如果我们只是需要旋转矩形(即`RotatedRect`)本身,那么它已经在那里了。根据问题描述,用户想要的是“椭圆外接矩形”。注意,`fitEllipse`返回的`RotatedRect`就是椭圆的最小外接矩形(旋转矩形)。所以,如果我们只需要这个旋转矩形,那么直接使用`RotatedRect`即可。如果我们想要轴对齐的外接矩形,我们可以通过以下步骤获得:步骤:1.从`RotatedRect`对象中获取其四个顶。2.将这些顶放入一个`vector<cv::Point>`中。3.对这个集调用`cv::boundingRect`,得到一个轴对齐的矩形(`cv::Rect`)。具体代码:假设我们有一个`vector<cv::RotatedRect>`,名为`rotatedRects`,我们可以这样处理:对于每个旋转矩形`rotatedRect`:```cpp//获取旋转矩形的四个顶cv::Point2fvertices[4];rotatedRect.points(vertices);//将四个顶转换为Point的vectorstd::vector<cv::Point>points;for(inti=0;i<4;i++){points.push_back(vertices[i]);}//计算这些的轴对齐外接矩形cv::RectaxisAlignedRect=cv::boundingRect(points);```这样,`axisAlignedRect`就是椭圆(或旋转矩形)的轴对齐外接矩形。但是,请注意:椭圆的实际轴对齐外接矩形并不一定等于旋转矩形的轴对齐外接矩形。因为旋转矩形是椭圆的最小外接矩形,而旋转矩形的轴对齐外接矩形可能会比椭圆的轴对齐外接矩形略大。不过,在大多数情况下,我们可以用旋转矩形的顶来计算轴对齐外接矩形作为近似。如果我们想要更精确的椭圆轴对齐外接矩形,我们需要计算椭圆在水平和垂直方向上的极值。这需要椭圆方程的极值,相对复杂。而用旋转矩形的四个顶计算轴对齐矩形是一种近似,通常也是可以接受的。因此,根据实际需,我们可以选择:1.直接使用`fitEllipse`返回的`RotatedRect`(即旋转矩形)作为外接矩形(最小外接矩形)。2.或者,通过上述方法得到轴对齐的外接矩形(近似)。现在,我们回答用户的问题:用户问:如何获取椭圆外接矩形?答案:-如果指的是最小外接矩形(旋转矩形),那么`fitEllipse`返回的`RotatedRect`本身就是。-如果指的是轴对齐的外接矩形,那么可以通过计算旋转矩形的四个顶,然后这些顶的轴对齐外接矩形来近似得到。代码示例(假设我们有一个`vector<cv::RotatedRect>ellipses`,存储了拟合的椭圆):```cppfor(size_ti=0;i<ellipses.size();i++){cv::RotatedRectrotatedRect=ellipses[i];//情况1:直接使用旋转矩形(最小外接矩形)//rotatedRect就是旋转矩形,我们可以使用它来绘制,例如://cv::ellipse(image,rotatedRect,...);//绘制椭圆//或者绘制旋转矩形://cv::Point2fvertices[4];//rotatedRect.points(vertices);//for(intj=0;j<4;j++)//cv::line(image,vertices[j],vertices[(j+1)%4],cv::Scalar(0,255,0),2);//情况2:计算轴对齐的外接矩形cv::Point2fvertices[4];rotatedRect.points(vertices);std::vector<cv::Point>points;for(intj=0;j<4;j++){points.push_back(vertices[j]);}cv::RectaxisAlignedRect=cv::boundingRect(points);//然后我们可以绘制这个轴对齐矩形//cv::rectangle(image,axisAlignedRect,cv::Scalar(255,0,0),2);}```注意:`cv::boundingRect`函数输入集,我们这里用的是旋转矩形的四个顶,所以得到的矩形是包围这个旋转矩形的轴对齐矩形,也就是包围椭圆的最小外接矩形的轴对齐外接矩形(近似椭圆的轴对齐外接矩形)。引用说明:-在OpenCV中,`cv::RotatedRect`类用于表示旋转矩形,它包含中心、大小和旋转角度。-函数`cv::boundingRect`用于计算集的最小直立(轴对齐)矩形[^1]。因此,我们可以根据需选择合适的外接矩形表示。如果用户需要精确的椭圆轴对齐外接矩形,那么需要计算椭圆在x和y方向上的极值。椭圆的参数方程可以表示为:$$x=cx+a\cdot\cos(\theta)\cdot\cos(\phi)-b\cdot\sin(\theta)\cdot\sin(\phi)$$$$y=cy+a\cdot\cos(\theta)\cdot\sin(\phi)+b\cdot\sin(\theta)\cdot\cos(\phi)$$其中,$(cx,cy)$是中心,$a$和$b$是半长轴和半短轴,$\phi$是旋转角度(注意OpenCV中角度的定义)。然后通过导找极值,这比较复杂,通常近似方法已经足够。但是,OpenCV并没有直接提供获取椭圆轴对齐外接矩形的函数。所以,我们通常采用旋转矩形顶计算轴对齐外接矩形的方法。总结:根据实际需选择使用旋转矩形(`RotatedRect`)或计算其顶的轴对齐外接矩形。相关问题:1.在OpenCV中,如何绘制拟合得到的椭圆?2.如何计算旋转矩形的面积?3.如何判断一个是否椭圆内部?4.如何计算椭圆的周长(或近似周长)?</think>在Qt和OpenCV的C++开发中,从`fitEllipse`函数返回的`vector<cv::RotatedRect>`对象获取椭圆外接矩形,本质上是提取每个`cv::RotatedRect`的最小外接矩形信息。以下是具体方法和步骤: --- ### **解决方案** #### **1. 理解`cv::RotatedRect`结构** `fitEllipse`返回的每个`cv::RotatedRect`对象包含椭圆的**最小外接旋转矩形**,其属性包括: - `center`:椭圆中心坐标 `(x, y)` - `size`:外接矩形的宽度和高度 `(width, height)`(对应椭圆的长轴和短轴) - `angle`:旋转角度(单位:度,范围 `[0, 180)`) #### **2. 直接获取外接矩形信息** 直接访问`cv::RotatedRect`的成员即可获取外接矩形的关键参数: ```cpp #include <opencv2/opencv.hpp> // 假设 ellipses 是 fitEllipse 返回的 vector<cv::RotatedRect> std::vector<cv::RotatedRect> ellipses = cv::fitEllipse(contours); for (const auto& rect : ellipses) { // 获取外接矩形中心 cv::Point2f center = rect.center; // 获取外接矩形尺寸(width = 长轴, height = 短轴) cv::Size2f size = rect.size; // 获取旋转角度(顺针方向) float angle = rect.angle; } ``` #### **3. 获取外接矩形的四个顶** 若需要绘制或计算外接矩形的边界使用`points()`方法: ```cpp for (auto& rect : ellipses) { cv::Point2f vertices[4]; rect.points(vertices); // 填充矩形的4个顶 // 示例:绘制外接矩形(在Qt图像上) for (int i = 0; i < 4; i++) { cv::line(image, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), // 绿色线条 2); // 线宽 } } ``` #### **4. 转换为轴对齐矩形(非旋转)** 若需要非旋转的矩形(`cv::Rect`),计算顶最小包围盒: ```cpp for (auto& rect : ellipses) { cv::Point2f vertices[4]; rect.points(vertices); // 计算轴对齐的包围矩形 cv::Rect boundingRect = cv::boundingRect(std::vector<cv::Point2f>(vertices, vertices + 4)); // boundingRect 包含 x, y, width, height } ``` --- ### **关键说明** - **外接矩形类型**:`fitEllipse`返回的是**最小旋转矩形**(`cv::RotatedRect`),而非轴对齐矩形。若需要后者,需额外计算顶包围盒[^1]。 - **椭圆参数**:`cv::RotatedRect.size`的`width`和`height`分别对应椭圆的长轴(2a)和短轴(2b),中心椭圆心。 - **角度定义**:`angle`是矩形相对于水平轴的旋转角度(顺针为正),可通过`cv::ellipse()`直接绘制椭圆。 --- ### **完整示例代码** ```cpp std::vector<std::vector<cv::Point>> contours; // ... (填充轮廓数据) // 拟合椭圆 std::vector<cv::RotatedRect> ellipses = cv::fitEllipse(contours); for (const auto& rect : ellipses) { // 1. 打印外接矩形参数 std::cout << "Center: " << rect.center << " Size: " << rect.size << " Angle: " << rect.angle << std::endl; // 2. 获取四个顶 cv::Point2f vertices[4]; rect.points(vertices); // 3. 计算轴对齐矩形 cv::Rect alignedRect = cv::boundingRect(std::vector<cv::Point2f>(vertices, vertices + 4)); } ``` --- ### **相关问题** 1. **如何绘制拟合的椭圆?** 使用`cv::ellipse(image, rotatedRect, color, thickness)`直接绘制[^1]。 2. **如何计算椭圆的面积?** 通过公式 $S = \pi \times \text{(长轴/2)} \times \text{(短轴/2)}$ 计算,或使用`cv::contourArea(contour)`。 3. **如何获取椭圆的最小外接圆?** 用`cv::minEnclosingCircle(contour, center, radius)`处理原始轮廓。 4. **`fitEllipse`的精度受哪些因素影响?** 轮廓数、噪声、拟合算法(基于最小二乘法)[^1]。 [^1]: 轮廓面积和轮廓周长:OpenCV对应函数包括`contourArea()`、`arcLength()`、`moments()`等,用于几何特征计算。 [^2]: OpenCV在计算机视觉领域应用广泛,结合Qt可实现高效开发。 [^3]: 《OpenCV计算机视觉开发实践:基于Qt C++》覆盖OpenCV 4.10与Qt C++实战案例。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昊虹AI笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值