学习OpenCV3——第三章:了解OpenCV的数据类型

一.OpenCV的数据类型

OpenCV有很多的数据类型,他们都基于一些重要视觉概念的抽象而设计,以此提供相对简单、直观的表示和处理。同时,许多算法开发者需要一些相对有效的,可以推广或拓展以满足他们特定需求的基本数据结构。OpenCV库使用基础数据类型模板构建并特化这些模板,从而使每个人能更简单的执行操作并满足自己的需求。从组织结构的角度来看,OpenCV的基础数据类型主要分为三类:

  • 直接从C++原语中继承的数据类型(如int和float等),这些类型主要包括简单的数组和矩阵,同时也代表一些简单的几何概念,比如点、矩形、大小等;

  • 辅助对象。这些对象代表更抽象的概念,比如垃圾收集指针类.......

  • 大型数组类型。这一类的典型代表是CV::Mat类.......

二.深入了解数据类型

在研究这些类时,我们将重点关注他们的接口而不是太具体的细节。同时,我们会提供一个例子案例告诉你能对这些对象做什么和不能做什么。对于一些底层的细节,建议查询.../opencv2/core.core.hpp文件。

三.基本类型

3-1.Point类

在大多数程序中,Point类是通过类似于cv::Point2i和cv::Point3f这类别名来实例化的,这些别名的最后一个字母表示构造该点所需要的原语(在这里,b是一个无符号字符,s是一个短整型,i是一个32位整型,f是一个32位浮点数,d是一个64位浮点数)。

表3-1:直接受Point类支持的操作
操作示例
默认构造函数

cv::Point2i p;

cv::Point3i p;

复制构造函数cv::Point3f p2(p1);
值构造函数

cv::Point2i(x0,x1);

cv::Point3d p(x0,x1,x2);

构造成固定向量类(cv::Vec3f) p;
成员访问p,x, p.y,  //and for three-dimensionalpoint classes:P.Z
点乘float x=p1.dot(p2);
双精度点乘double x=p1.dot(p2);
叉乘p1,cross(p2);  //for three-dimensional point classes only
判断一个点p是否在矩形r内p.inside(r);  //for two-dimensional point classes only

3-2.cv::Scalar类

cv::Scalar是四维点类。与其他类型相似,它实际上与一个模板类相关,但访问他的别名返回一个该模板的实例,在这个模板中,所有的成员函数都是双精度浮点数。在计算机视觉中,cv::Scalar类有一些与四元向量相关的特殊成员函数,表3-2列举了一些cv::Scalar支持的操作。

表3-2:cv::Scalar类支持的操作
操作示例
默认构造函数cv::Scalar s;
复制构造函数cv::Scalar s2(s1);
值构造函数cv::Scalar s(x0);  cv::Scalar s(x0,x1,x2,x3);
元素相乘s1.mul(s2);
(四元数)共轭s.conj();  //returns cv::Scalar(s0,-s1,-s2,-s3):
(四元数)真值测试s.isReal();  //returns true, if(s1==s2==s3==0)

3-3.size类

size类在实际操作时与Point类相似,而且可以与Point类互相转换。表3-3列举了size类支持的操作。 

表3-3:size类直接支持的操作
操作示例
默认构造函数

cv::Size sz;

cv::Size2i sz;

cv::Size2f sz;

复制构造函数cv::Size sz2(sz1);
值构造函数cv::Size2f sz(w,h);
成员访问sz.width; sz.height;
计算面积sz.area();

3-4.Rect类

矩形类包含Point类的成员x和y(矩形左上角)和size类的成员width和height(代表矩形的大小)。然而矩形类并不是从Point类或size类继承过来的,所以它并没有从他们那里继承操作(表3-4)。

表3-4:cv::Rcet直接支持的操作
操作示例
默认构造函数cv::Rcet r;
拷贝构造函数cv::Rect r2(r1);
值构造函数cv::Rect (x,y,w,h);
由起始点和大小构造cv::Rect(p,sz);
由两个对角构造cv::Rect(p1,p2);
成员访问r.x; r.y; r.width; r.height;
计算面积r.zrea();
提取左上角r.tl();
提取右上角r.br();
判断点p是否在矩形r内r.contains(p);
表3-5:cv::Rect对象的覆写操作符
操作示例
矩形r1和矩形r2的交集cv::Rect r3 = r1 & r2;  r1 &= r2;
同时包含矩形r1和矩形r2的最小面积矩形cv::Rect r3 = r1 | r2;  r1 |= r2;
平移矩形r  x个数量cv::Rect rx = r + x;  r += x;
扩大矩形r  s大小cv::Rect rs = r + s;  r += s;
比较矩形r1与矩形r2是否相等bool eq = (r1 ==r2);
比较矩形r1和矩形r2是否不相等bool ne = (r1  != r2);

3-5.cv::RotatedRect类

cv::RotatedRect类是OpenCV中少数底层没有使用模板的C++接口类之一。同时,它是包含一个中心点cv::Point2f、一个大小cv::Size2f和一个额外的角度float的容器。其中浮点类型(float)的角度代表图形绕中心点旋转的角度。cv::RotatedRect和cv::Rect有一个非常重要的不同点是cv::RotatedRect是以中心为原点的,而cv::Rect则位于左上角为远点。表3-6列举了cv::RotatedRect类直接支持的操作。

表3-6:cv::RotatedRect直接支持的操作
操作示例
默认构造函数cv::RotatedRect rr();
复制构造函数cv::RotatedRect rr2(rr1);
从两个点构造cv::RotatedRect(p1, p2);
值构造函数,需要一个点(point)、一个大小(size)、和一个角度(angle)cv::RotatedRect rr(p, sz, theta);
成员访问rr.center,  rr.size,  rr.angle
 返回四个角的列表rr.points(pts[4]);

3-6.固定矩阵类

固定矩阵类是为编译时就已知维度的矩阵打造的,这也是它称为“固定”的原因。这个模板被称为cv::Matx<>,一般来说,当你要表示一盒用来处理矩阵代数的矩阵的时候,你就会用到固定矩阵类。而如果你的对象是一个像图像或大型点列表这样的大数组,使用固定矩阵类就不是个好主意。这种情况应该用Mat(我们将在后面介绍到)。

感觉很少用到,先不做介绍,以后有时间再补,如若需要,可看这里https://docs.opencv.org/master/de/de1/classcv_1_1Matx.html

3-7.固定向量类

固定向量类是从固定矩阵类派生出来的。他们其实只是为了更方便地使用cv::Matx<>。在C++继承的意义上,可以说固定向量模板cv::Vec是列为1的cv::Matx<>。为特定实例准备好的别称有这样的形式cv::Vec{2,3,4,5}{b,s,w,i,f,d},最后一个字母意义如前文所述(另外加上w,表示unsigned short)。表3-8展示了cv::Vec支持的操作。

表3-8:cv::Vec支持的操作
操作示例
默认构造函数Vec2s v2s;    Vec6f v6f;
复制构造函数Vec3f u3f(v3f);

值构造函数

Vec2f v2f(x0,x1); Vec6d v6d(x0,x1,x2,x3,x4,x5);
成员访问v4f[i]; v3w(j);  //operator() and operator[] both work
向量叉乘v3f.cross(u3f);

四.辅助对象

4-1.cv::TermCriteria类

很多算法需要一个终止条件以确定何时退出。通常,终止条件的形式要么是达到允许的有限迭代次数(称为COUNT或MAX_ITER),要么是某种形式的误差参数(如果接近于此程度,就可以退出,称为EPS,即epsilon的简称)。cv::TermCriteria对象把一个或两个终止条件封装,以方便传进OpenCV算法函数里。他们有三个成员变量(type,maxCount以及epsilon),都可以直接设置(它们是共有的),更常见的做法是只通过他们的构造函数TermCriteria(int  type,  int  maxCount, double epsilon)进行设置。变量type设置为cv::TermCriteria::COUNT或者cv::TermCriteria::EPS。也可以把两个条件并(使用位运算符:|)在一起。cv::TermCriteria::COUNT是cv::TermCriteria::MAX_ITER的同义词,所以如果喜欢,也可以使用后者。如果终止条件包含cv::TermCriteria::COUNT,就是告诉算法在maxCount次迭代之后终止。如果终止条件包含cv::TermCriteria::EPS,就是高速算法在与算法收敛相关的某些度量降到epsilon以下后终止。

4-2.cv::Range类

cv::Range类用于确定一个连续的整数数列,它包含 start和end 成员变量。通常情况下cv::Range包含start值但不包含end值,例如:cv::Range rng(0,4)包含0,1,2,3但不包含4。

4-3.cv::Ptr模板和垃圾收集

智能指针(smart pointer)是C++中一个非常有用的类型。这个指针允许我们创建一个对象的引用,然后把它传递到各处。你可以创建更多的对该对象的引用,然后所有这些引用都会被计数。当引用超出范围,智能指针的引用计数就会减少。一旦所有的引用(指针的实例)消失,这个对象将会自动清理(释放)。而作为程序员的你,不再需要记录这些东西。

实现方法有两种:

  • cv::Ptr<Matx33f>  p(new  cv::Matx33f)
  • cv::Ptr<Matx33f> p = makePtr<cv::Matx33f>();

4-4.cv::Exception 类和异常处理

OpenCV3继承STL的 std::exception 异常定义了自己的 cv::Exception 异常类。cv::Exception 包含以下几个变量: code, err, func, file和line ,通过这几个变量可以很快定位和查询异常信息。使用以下方式可以定义自己的异常:

  • CV_Error( errorcode, description );
  • CV_Error_( errorcode, printf_fmt_str, [printf-args] );
  • CV_Assert( condition );  
  • CV_DbgAssert( condition );   

4-5.cv::DataType<>模板

cv::DataType<>用于给基础类型提供说明描述,在c++中这种技术称为类特性。简言之,也就是记录某种数据类型深度多少,有几个通道,格式是什么等。定义如下:

template<typename _Tp> class DataType
{
    typedef _Tp value_type;
    typedef value_type work_type;
    typedef value_type channel_type;
    typedef value_type vec_type;
    enum {
        generic_type = 1,
        depth = -1,
        channels = 1,
        fmt = 0,
        type = CV_MAKETYPE(depth, channels)
    };
};


为了更好地理解,我们来看来自core.hpp的两个示例:

// Defination for float
template<> class DataType<float>
{
public:
    typedef float value_type;
    typedef value_type work_type;
    typedef value_type channel_type;
    typedef value_type vec_type;
    enum {
        generic_type = 0,
        depth = DataDepth<channel_type>::value,
        channels = 1,
        fmt = DataDepth<channel_type>::fmt,
        type = CV_MAKETYPE(depth, channels)
    };
};


其中,value_type是float类型,work_type, channel_type和vec_type同样也是float类型;generic_type设置为0,且在core.hpp中的所有类型都被设置为0; depth由cv::DataDepth::value 定义,它的值为CV_32F;channels为1,因为float为单独的一个数;fmt 由cv::DataDepth::fmt 定义,它的值为f;type由CV_MAKETYPE(CV_32F,1) 确定为CV_32FC1 。这样,对于float类型,DataType可以为它提供很好的解释。 下一个例子:

// Defination for cv::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;
    typedef Vec<channel_type, channels> vec_type;
    enum {
        generic_type = 0,
        depth = DataDepth<channel_type>::value,
        channels = 4,
        fmt = ((channels-1)<<8) + DataDepth<channel_type>::fmt,
        type = CV_MAKETYPE(depth, channels)
    };
};

4-6.cv::InputArray类和cv::OutputArray类

cv::InputArray和cv::OutputArray代指所有的数组类型,使用它们可以简化输入输出而不需要关心具体的类型,更像是一种数组容器。cv::InputArray默认是const的,即只读的;而cv::OutputArray则无此限制。当无需输入或输出时,可以使用 cv::noArray() 。


五.工具函数

工具函数包含数学操作、测试、错误生成、内存与线程处理、优化及其他的工具。表3-10列举了这些函数并概括了他们的功能,详细描述紧随其后。

表3-10:工具函数和系统函数
函数名称描述
cv::alignPtr()对齐指针到给定字节数
cv::alignSize()将缓冲区大小与给定的字节数对齐
cv::allocate()分配一个C风格的数组对象
cvCeil()近似一个浮点数x到不小于x的最近的整数(向上取整)
cv::cubeRoot()计算一个数的立方根
cv::CV_Assert()如果给定的条件不为真,则抛出异常
CV_Error()构造cv::Exception(从固定的字符串)并抛出异常的一个宏
CV_Error_()构造cv::Exception(从格式化的字符串)并抛出异常的一个宏
cv::deallocate()释放一个C风格的数组对象
cv::error()指示错误并抛出异常
cv::fastAtan2()向量的二维角度的计算
cv::fastFree()释放一个内存缓冲区
cv::fastMalloc()分配一个对齐的内存缓冲区
cvFloor()近似一个浮点数x到不大于x的最近的整数(向下取整)
cv::format()以sprintf类似格式创建一个STL字符串
cv::getCPUTickCount()从内部CPU计时器获得tick计数
cv::getNumThreads()获得当前OpenCV使用的线程数
cv::getOptimalDFTSize()计算要传递给cv::DFT()的数组的最适宜大小
cv::getThreadNum()获得当前线程的索引
cv::getTickCount()获得系统的tick计数
cv::getTickFrequency()获得每秒的tick数
cvIsInf()判断一个浮点数x是否无穷
cvIsNaN()判断一个浮点数x是否不是一个数
cvRound()近似一个浮点数x到最近的整数
cv::setNumThreads()设定OpenCV使用的线程数
cv::setUseOptimized()开启或关闭优化代码(SSE2等)
cv::useOptimized()指示代码优化的启用(请见cv::setUseOptimized())

六.小结

在这一章,我们详细学习了OpenCV库中用以处理紧凑数据的数据类型,包括点、低维向量、常用来表示颜色或者坐标的矩阵、以及在这些空间上操作的小矩阵。我们学习了用于此类对象主要是内部的模板表示以及这些模板的特化类。这些特化类最为常用。除了这些数据类之外,我们还学习了帮助对象,这些对象允许我们表示终止条件和值范围等概念。最后,我们通过提供一些使用函数来总结本章。这些函数提供了计算机视觉应用程序经常遇到的重要任务的优化实现。我们还提供了包括特殊的运算和内存管理工具的重要操作例子。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值