目录

​一、前言​

​二、温故知新​

​1、基础结构都有啥​

​2、Point_​

​3、Size_​

​三、Rect_​

​1、定义​

​1.构造函数​

​2.基本操作​

​3.成员变量​

​4.使用时的数据类型​

​2、常用方法​

​1.定义中的方法​

​2.常用运算​

​3、代码实战​


一、前言

上一篇文章,我们讲了OpenCV中的基础结构,还讲了两个最常用也是最基本的结构,今天这篇博客,我们来讲剩下两个常见的结构。

二、温故知新

1、基础结构都有啥

上一节课,我们讲到了基础结构,那我们都讲到哪些结构呢?跟我一起来回顾一下吧!

1.Complex:这个是复数类,跟我们数学上学到的复数是一样的。

2.Point_:表示的是二维点,包括两个坐标坐标值,也包括最常见的点的相关操作。

3.Point3_:表示三维点,包括三个坐标值:

4.Size_:表示图像或矩形大小。包括两个成员变量:width和height,表示图像或者矩阵的大小。

5.Rect_:这个用于描述二维矩形,主要有两个部分的参数:

(1)图像矩阵的左上角坐标。

(2)图像矩阵的宽度和高度。

6.RotatedRect:带有旋转角度的矩形。主要有三个部分的参数:

(1)矩形的中心坐标。

(2)矩形长宽。

(3)图像旋转角度。

7.Range:表示图像的连续子序列。

8.Scalar_:常用于定义像素值。

9.KeyPoint:用于角点检测。

10.DMatch:用于查询描述符索引、列车描述符索引、列车图像索引和描述符之间的距离。

11.TermCriteria:定义迭代算法终止条件的类。我们可以使用默认构造函数初始化它,然后重写任何参数,或者可以使用构造函数的高级变量完全初始化结构。

2、Point_

然后,我们又详细讲解了Point_类,讲了它的基本定义和常见用法。

Point_类有两个成员变量:

_Tp x; //!< x coordinate of the point
_Tp y; //!< y coordinate of the point

有多个构造函数:

//! default constructor
Point_();
Point_(_Tp _x, _Tp _y);
Point_(const Point_& pt);
Point_(Point_&& pt) CV_NOEXCEPT;
Point_(const Size_<_Tp>& sz);
Point_(const Vec<_Tp, 2>& v);

还有很多常用操作,因为内容比较多,就不再在这里说明啦!大家可以打开上一篇博客去详细查看哦:

Point_类常用方法

3、Size_

然后,我们又详细讲解了Size_类,讲了它的基本定义和常见用法。

Size_类也有两个成员变量:

_Tp width; //!< the width
_Tp height; //!< the height

有多个构造函数:

//! default constructor
Size_();
Size_(_Tp _width, _Tp _height);
Size_(const Size_& sz);
Size_(Size_&& sz) CV_NOEXCEPT;
Size_(const Point_<_Tp>& pt);

还有很多常用操作,因为内容比较多,就不再在这里说明啦!大家可以打开上一篇博客去详细查看哦:

Size_类常用方法

接下来让我们进入一个新的结构。

三、Rect_

除了上面两个最基本的就是Rect_了,我们怎么理解Rect_呢?

一个明确位置且横平竖直的矩形。

比如下面这几个:

【opencv4.3.0教程】05之基础结构2之矩形结构Rect_详解_Rect

一般来说,我们构建这个矩形,可以通过如下方法:

1.一个定位点,矩形的长和宽;

2.两个定位点(要求分别为对角线);

这是我们最基本的理解方式,了解了这些,就让我们从定义出发,一步一步来了解它吧!

1、定义

跟上一次一样,我们先从定义入手,对它有个最基本的认识:

template<typename _Tp> class Rect_
{
public:
typedef _Tp value_type;

//! default constructor
Rect_();
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
Rect_(const Rect_& r);
Rect_(Rect_&& r) CV_NOEXCEPT;
Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);
Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);

Rect_& operator = ( const Rect_& r );
Rect_& operator = ( Rect_&& r ) CV_NOEXCEPT;
//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;

//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
//! true if empty
bool empty() const;

//! conversion to another data type
template<typename _Tp2> operator Rect_<_Tp2>() const;

//! checks whether the rectangle contains the point
bool contains(const Point_<_Tp>& pt) const;

_Tp x; //!< x coordinate of the top-left corner
_Tp y; //!< y coordinate of the top-left corner
_Tp width; //!< width of the rectangle
_Tp height; //!< height of the rectangle
};

typedef Rect_<int> Rect2i;
typedef Rect_<float> Rect2f;
typedef Rect_<double> Rect2d;
typedef Rect2i Rect;

template<typename _Tp> class DataType< Rect_<_Tp> >
{
public:
typedef Rect_<_Tp> value_type;
typedef Rect_<typename DataType<_Tp>::work_type> work_type;
typedef _Tp channel_type;

enum { generic_type = 0,
channels = 4,
fmt = traits::SafeFmt<channel_type>::fmt + ((channels - 1) << 8)
#ifdef OPENCV_TRAITS_ENABLE_DEPRECATED
,depth = DataType<channel_type>::depth
,type = CV_MAKETYPE(depth, channels)
#endif
};

typedef Vec<channel_type, channels> vec_type;
};

namespace traits {
template<typename _Tp>
struct Depth< Rect_<_Tp> > { enum { value = Depth<_Tp>::value }; };
template<typename _Tp>
struct Type< Rect_<_Tp> > { enum { value = CV_MAKETYPE(Depth<_Tp>::value, 4) }; };
} // namespace

这里面最基本的定义主要包括如下三部分:

1.构造函数

几个构造函数,用于生成Rect对象:

//! default constructor
Rect_();
Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height);
Rect_(const Rect_& r);
Rect_(Rect_&& r) CV_NOEXCEPT;
Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz);
Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2);

 对于第一个构造函数,可以创建一个空的矩形,左上角顶点坐标为(0,0),矩形的长宽均为0。一般这种无参构造函数都是创建空的对象,值的初始化要么为空,要么为0。

我们上面说到,想要构造一个矩形,可以有两种方式:

第一种方式是使用一个点的坐标和长宽。

(1)对于这种方式,我们既可以给四个参数:横坐标、纵坐标、长、宽:

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

(2)也可以使用我们昨天提到的两个类型:Point_和Size_。

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

第二种方式是使用两个对角线顶点:

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

除了上面的两种方法,我们还有一种方法就是使用另外的矩形为该矩形赋值:

Rect_(const Rect_& r);
Rect_(Rect_&& r) CV_NOEXCEPT;

 

2.基本操作

在定义中,还有如下基本操作:

Rect_& operator = ( const Rect_& r );
Rect_& operator = ( Rect_&& r ) CV_NOEXCEPT;
//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;

//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
//! true if empty
bool empty() const;

//! conversion to another data type
template<typename _Tp2> operator Rect_<_Tp2>() const;

//! checks whether the rectangle contains the point
bool contains(const Point_<_Tp>& pt) const;

我们分类说明一下,方便大家理解:

第一类,基本赋值操作

Rect_& operator = ( const Rect_& r );
Rect_& operator = ( Rect_&& r ) CV_NOEXCEPT;

这个跟上面讲到的使用别的矩形为矩形赋值的功能是一致的;

第二类,求顶点,获取矩形的左上角顶点和右下角顶点的坐标

//! the top-left corner
Point_<_Tp> tl() const;
//! the bottom-right corner
Point_<_Tp> br() const;

第三类,长宽系列,包括获取长宽,利用长宽求面积,利用长宽判断是否为空

//! size (width, height) of the rectangle
Size_<_Tp> size() const;
//! area (width*height) of the rectangle
_Tp area() const;
//! true if empty
bool empty() const;

第四类,转化为其他类型

//! conversion to another data type
template<typename _Tp2> operator Rect_<_Tp2>() const;

第五类,判断矩形是否包含某点,跟在点中的函数是一个含义

//! checks whether the rectangle contains the point
bool contains(const Point_<_Tp>& pt) const;

3.成员变量

四个类体成员变量,包括横纵坐标,还有矩形的长和宽:

_Tp x; //!< x coordinate of the top-left corner
_Tp y; //!< y coordinate of the top-left corner
_Tp width; //!< width of the rectangle
_Tp height; //!< height of the rectangle

4.使用时的数据类型

当我们定义了Rect_类之后,跟上面一样,我们要定义具体的使用过程中的类型:

typedef Rect_<int> Rect2i;
typedef Rect_<float> Rect2f;
typedef Rect_<double> Rect2d;
typedef Rect2i Rect;

 

2、常用方法

接下来我们要说的就是方法,这里有很多实现了上面的类定义时的方法,我们在上面也具体讲解了,在这里我们讲一下具体的实战。

1.定义中的方法

定义中的方法包括构造函数和几个常用方法,构造函数如下:

template<typename _Tp> inline
Rect_<_Tp>::Rect_()
: x(0), y(0), width(0), height(0) {}

template<typename _Tp> inline
Rect_<_Tp>::Rect_(_Tp _x, _Tp _y, _Tp _width, _Tp _height)
: x(_x), y(_y), width(_width), height(_height) {}

template<typename _Tp> inline
Rect_<_Tp>::Rect_(const Rect_<_Tp>& r)
: x(r.x), y(r.y), width(r.width), height(r.height) {}

template<typename _Tp> inline
Rect_<_Tp>::Rect_(Rect_<_Tp>&& r) CV_NOEXCEPT
: x(std::move(r.x)), y(std::move(r.y)), width(std::move(r.width)), height(std::move(r.height)) {}

template<typename _Tp> inline
Rect_<_Tp>::Rect_(const Point_<_Tp>& org, const Size_<_Tp>& sz)
: x(org.x), y(org.y), width(sz.width), height(sz.height) {}

template<typename _Tp> inline
Rect_<_Tp>::Rect_(const Point_<_Tp>& pt1, const Point_<_Tp>& pt2)
{
x = std::min(pt1.x, pt2.x);
y = std::min(pt1.y, pt2.y);
width = std::max(pt1.x, pt2.x) - x;
height = std::max(pt1.y, pt2.y) - y;
}

常用方法如下:

template<typename _Tp> inline
Point_<_Tp> Rect_<_Tp>::tl() const
{
return Point_<_Tp>(x,y);
}

template<typename _Tp> inline
Point_<_Tp> Rect_<_Tp>::br() const
{
return Point_<_Tp>(x + width, y + height);
}

template<typename _Tp> inline
Size_<_Tp> Rect_<_Tp>::size() const
{
return Size_<_Tp>(width, height);
}

template<typename _Tp> inline
_Tp Rect_<_Tp>::area() const
{
const _Tp result = width * height;
CV_DbgAssert(!std::numeric_limits<_Tp>::is_integer
|| width == 0 || result / width == height); // make sure the result fits in the return value
return result;
}

template<typename _Tp> inline
bool Rect_<_Tp>::empty() const
{
return width <= 0 || height <= 0;
}

template<typename _Tp> template<typename _Tp2> inline
Rect_<_Tp>::operator Rect_<_Tp2>() const
{
return Rect_<_Tp2>(saturate_cast<_Tp2>(x), saturate_cast<_Tp2>(y), saturate_cast<_Tp2>(width), saturate_cast<_Tp2>(height));
}

template<typename _Tp> inline
bool Rect_<_Tp>::contains(const Point_<_Tp>& pt) const
{
return x <= pt.x && pt.x < x + width && y <= pt.y && pt.y < y + height;
}

我们使用构造函数创建几个矩形:

Rect r1 = Rect();
Rect r2 = Rect(1, 2, 3, 4);
Rect r3 = Rect(Point(5, 5), Size(10, 10));
Rect r4 = Rect(Point(5, 6), Point(10, 10));
Rect r5 = Rect(r4);

然后我们调用常用方法,查看一下效果:

cout << "r1 = " << r1 << endl;
cout << "r2 = " << r2 << endl;
cout << "r3 = " << r3 << endl;
cout << "r4 = " << r4 << endl;
cout << "r5 = " << r5 << endl;
cout << "【r5 info】" << endl;
cout << "r5.x = " << r5.x << endl;
cout << "r5.y = " << r5.y << endl;
cout << "r5.width = " << r5.width << endl;
cout << "r5.height = " << r5.height << endl;
cout << "r5.size = " << r5.size() << endl;
cout << "r5.area = " << r5.area() << endl;
cout << "r5.br = " << r5.br() << endl;
cout << "r5.tl = " << r5.tl() << endl;

if (r4 == r5) cout << "r4 = r5" << endl;
else cout << "r4 != r5" << endl;
if (r5.contains(Point())) cout << "Point" << Point() << " 在 Rect" << r5 << "中!" << endl;
else cout << "Point" << Point() << " 不在 Rect" << r5 << "中!" << endl;

执行结果如下:

【opencv4.3.0教程】05之基础结构2之矩形结构Rect_详解_矩形_02

 

2.常用运算

常用运算包括赋值运算,四则运算等,具体如下:

1.让左上角定位点移位的加赋值与减赋值,及其相关运算:

template<typename _Tp> static inline
Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Point_<_Tp>& b )
{
a.x += b.x;
a.y += b.y;
return a;
}

template<typename _Tp> static inline
Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Point_<_Tp>& b )
{
a.x -= b.x;
a.y -= b.y;
return a;
}

template<typename _Tp> static inline
Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Point_<_Tp>& b)
{
return Rect_<_Tp>( a.x + b.x, a.y + b.y, a.width, a.height );
}

template<typename _Tp> static inline
Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Point_<_Tp>& b)
{
return Rect_<_Tp>( a.x - b.x, a.y - b.y, a.width, a.height );
}

2.改变矩形尺寸的加赋值与减赋值,及其相关运算

template<typename _Tp> static inline
Rect_<_Tp>& operator += ( Rect_<_Tp>& a, const Size_<_Tp>& b )
{
a.width += b.width;
a.height += b.height;
return a;
}

template<typename _Tp> static inline
Rect_<_Tp>& operator -= ( Rect_<_Tp>& a, const Size_<_Tp>& b )
{
const _Tp width = a.width - b.width;
const _Tp height = a.height - b.height;
CV_DbgAssert(width >= 0 && height >= 0);
a.width = width;
a.height = height;
return a;
}

template<typename _Tp> static inline
Rect_<_Tp> operator + (const Rect_<_Tp>& a, const Size_<_Tp>& b)
{
return Rect_<_Tp>( a.x, a.y, a.width + b.width, a.height + b.height );
}

template<typename _Tp> static inline
Rect_<_Tp> operator - (const Rect_<_Tp>& a, const Size_<_Tp>& b)
{
const _Tp width = a.width - b.width;
const _Tp height = a.height - b.height;
CV_DbgAssert(width >= 0 && height >= 0);
return Rect_<_Tp>( a.x, a.y, width, height );
}

3.两个矩形的公共矩形,如果没有,就是空:

【opencv4.3.0教程】05之基础结构2之矩形结构Rect_详解_构造函数_03

template<typename _Tp> static inline
Rect_<_Tp>& operator &= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
{
_Tp x1 = std::max(a.x, b.x);
_Tp y1 = std::max(a.y, b.y);
a.width = std::min(a.x + a.width, b.x + b.width) - x1;
a.height = std::min(a.y + a.height, b.y + b.height) - y1;
a.x = x1;
a.y = y1;
if( a.width <= 0 || a.height <= 0 )
a = Rect();
return a;
}

template<typename _Tp> static inline
Rect_<_Tp> operator & (const Rect_<_Tp>& a, const Rect_<_Tp>& b)
{
Rect_<_Tp> c = a;
return c &= b;
}

4.两个矩形的最小包围矩形

【opencv4.3.0教程】05之基础结构2之矩形结构Rect_详解_成员变量_04

template<typename _Tp> static inline
Rect_<_Tp>& operator |= ( Rect_<_Tp>& a, const Rect_<_Tp>& b )
{
if (a.empty()) {
a = b;
}
else if (!b.empty()) {
_Tp x1 = std::min(a.x, b.x);
_Tp y1 = std::min(a.y, b.y);
a.width = std::max(a.x + a.width, b.x + b.width) - x1;
a.height = std::max(a.y + a.height, b.y + b.height) - y1;
a.x = x1;
a.y = y1;
}
return a;
}

template<typename _Tp> static inline
Rect_<_Tp> operator | (const Rect_<_Tp>& a, const Rect_<_Tp>& b)
{
Rect_<_Tp> c = a;
return c |= b;
}

5.判断两个矩形是否相等

template<typename _Tp> static inline
bool operator == (const Rect_<_Tp>& a, const Rect_<_Tp>& b)
{
return a.x == b.x && a.y == b.y && a.width == b.width && a.height == b.height;
}

template<typename _Tp> static inline
bool operator != (const Rect_<_Tp>& a, const Rect_<_Tp>& b)
{
return a.x != b.x || a.y != b.y || a.width != b.width || a.height != b.height;
}

比较简单,我们就通过代码实战来巩固一下吧!

3、代码实战

接下来我们走进实战,为我们以后的使用打好基础吧。

Rect rect1 = Rect(Point(5, 5), Point(15, 15));
Rect rect2 = Rect(Point(7, 7), Point(20, 20));
Point point1 = Point(3, 3);
Size size1 = Size(4, 4);

rect1 += point1;
cout << "rect1 += point1 = " << rect1 << endl;
rect1 = rect1 - point1;
cout << "rect1 - point1 = " << rect1 << endl;

rect2 += size1;
cout << "rect2 += size1 = " << rect2 << endl;
rect2 = rect2 - size1;
cout << "rect2 - size1 = " << rect2 << endl;

cout << "rect1 & rect2 = " << (rect1 & rect2) << endl;
cout << "rect1 | rect2 = " << (rect1 | rect2) << endl;

【opencv4.3.0教程】05之基础结构2之矩形结构Rect_详解_常用方法_05

今天的内容就到这里啦,大家一定要多做练习呀!