目录
一、前言
二、温故知新
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_呢?
一个明确位置且横平竖直的矩形。
比如下面这几个:
一般来说,我们构建这个矩形,可以通过如下方法:
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;
执行结果如下:
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.两个矩形的公共矩形,如果没有,就是空:
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.两个矩形的最小包围矩形:
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;
今天的内容就到这里啦,大家一定要多做练习呀!