Opencv学习----基本结构对象-几何对象(cv :: Point、cv::Rect、cv::RotatedRect)

本文深入探讨了OpenCV中的几何对象类,包括2D和3D点、矩形及旋转矩形。详细介绍了各类的定义、成员变量、构造函数、操作符重载以及成员方法。涵盖了坐标转换、向量算术、点积、叉积、矩形包含性检查等关键功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4.3.1 cv :: Point_ <_Tp>

4.3.1.1 定义

2D点的模板类。

该类的实例可与C结构CvPoint和CvPoint2D32f互换。还有一个强制转换操作符可将点坐标转换为指定的类型。从浮点坐标到整数坐标的转换是通过舍入完成的。通常,转换对每个坐标使用此操作。除了上述声明中列出的类成员外,还实现了以下关于点的操作:

pt1 = pt2 + pt3;
pt1 = pt2 - pt3;
pt1 = pt2 * a;
pt1 = a * pt2;
pt1 = pt2 / a;
pt1 += pt2;
pt1 -= pt2;
pt1 *= a;
pt1 /= a;
double value = norm(pt); // L2 norm
pt1 == pt2;
pt1 != pt2;

为方便起见,定义了以下类型别名:

typedef Point_ <int> Point2i ;

typedef Point2i Point ;

typedef Point_ <float> Point2f ;

typedef Point_ <double> Point2d ;

4.3.1.2 成员和接口

成员:

_Tp x;

点的x坐标

_Tp y;

点的y坐标

 

接口:

Point_();

 

Point_(_Tp _x, _Tp _y);

 

Point_(const Point_& pt);

 

Point_(const Vec<_Tp, 2>& v);

 

Point_& operator = (const Point_& pt);

 

_Tp dot(const Point_& pt) const;

点积

double ddot(const Point_& pt) const;

用双精度算术计算的点积

double cross(const Point_& pt) const;

叉积

bool inside(const Rect_<_Tp>& r) const;

检查该点是否在指定的矩形内

 

4.3.2 cv::Point3_< _Tp >

4.3.1.1 定义

3D点的模板类。

该类的实例可与C结构CvPoint2D32f相互转换。与Point_类似,3D点的坐标可以转换为另一种类型。还支持向量算术和比较操作。

以下Point3_ <>别名可用:

typedef Point3_ <int> Point3i ;

typedef Point3_ <float> Point3f ;

typedef Point3_ <double> Point3d ;

4.3.1.2 成员和接口

成员:

_Tp x;

 

_Tp y;

 

_Tp z;

 

 

接口:

Point3_();

 

Point3_(_Tp _x, _Tp _y, _Tp _z);

 

Point3_(const Point3_& pt);

 

Point3_(const Vec<_Tp, 3>& v);

 

Point3_& operator = (const Point3_& pt);

 

_Tp dot(const Point3_& pt) const;

 

double ddot(const Point3_& pt) const;

 

Point3_ cross(const Point3_& pt) const;

 

 

4.3.3 cv::Rect_< _Tp >

4.3.3.1 定义

2D矩形的模板类。

4.3.3.2 成员和接口

成员:

_Tp x;

左上角的x坐标

_Tp y;

左上角的y坐标

_Tp width;

矩形宽度

_Tp height;

矩形高

 

接口:

Rect_();

 

Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);

 

Rect_(const Rect_& r);

 

Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);

 

Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);

 

Rect_& operator = ( const Rect_& r );

 

Point_<_Tp> tl() const;

左上点

Point_<_Tp> br() const;

右下点

Size_<_Tp> size() const;

宽、高

_Tp area() const;

面积

bool empty() const;

是否为空

bool contains(const Point_<_Tp>& pt) const;

检查矩形是否包含该点

4.3.4 cv::RotatedRect

4.3.4.1 定义

该类表示平面上的旋转(即非右上)矩形。每个矩形由中心点(质心),每边的长度(由Size2f结构表示)和以度为单位的旋转角度指定。

4.3.4.2 成员和接口

成员:

Point2f center;

矩形中心点

Size2f size;

矩形的宽、高

float angle;

旋转角度。当角度为0、90、180、270等时,矩形变为右上矩形。

 

接口:

RotatedRect();

 

RotatedRect(const Point2f& center, const Size2f& size, float angle);

 

RotatedRect(const Point2f& point1, const Point2f& point2, const Point2f& point3);

旋转矩形的任意3个端点。它们必须按顺序给出(顺时针或逆时针)。

void points(Point2f pts[]) const;

返回矩形的4个顶点。顺序是左下角,左上角,右上角,右下角。

Rect boundingRect() const;

返回包含旋转矩形的最小上下整数矩形

Rect_<float> boundingRect2f() const;

返回包含旋转矩形的最小(精确)浮点矩形,不用于图像

<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++实战案例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dylan55_you

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

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

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

打赏作者

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

抵扣说明:

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

余额充值