opencv2.0 DataType

从2.0开始,opencv采用c++来重写代码,既然是c++,自然少不了模板类,所以DataType是模板类的集合。


官方的描述:


DataType

class DataType
    Template “trait” class for OpenCV primitive data types. 
    A primitive OpenCV data type is one of unsigned char, bool,
    signed char, unsigned short, signed short, int, float, double,
    or a tuple of values of one of these types,
    where all the values in the tuple have the same type. 

是opencv最基础的数据类型了,它是一些c++基础数据类型的组合。


Point_ 类(在core.hpp里)

注:类名后面带下划线,这个是指模板类,以后不再重申。

/*!
  template 2D point class.
  
  The class defines a point in 2D space. Data type of the point coordinates is specified
  as a template parameter. There are a few shorter aliases available for user convenience. 
  See cv::Point, cv::Point2i, cv::Point2f and cv::Point2d.
*/  
template<typename _Tp> class CV_EXPORTS Point_
{
public:
    typedef _Tp value_type;
    // ... 略去所有函数
    _Tp x, y; //< the point coordinates
};

可以看到,这是2维点的原型,成员边量就两个x,y.   _Tp是模板类的参数,又被重命名为value_type了。

所以我们可以取_Tp为很多c++的基本数据类型,如int,float,double...

因此,就有一堆实际类了,

比如:Point_<int>,Point_<float>,Point_<double>

为了方便用户使用,opencv都给这些取了别名

/*!
  \typedef
  
  shorter aliases for the most popular cv::Point_<> specializations
*/
typedef Point_<int> Point2i;
typedef Point_<float> Point2f;
typedef Point_<double> Point2d;

其中,还为最最常用的Point_<int>取了别名

typedef Point2i Point;


从上面可以看出opencv定义基本数据类型的套路...接下来的其他数据结构都是这样...所以后面部分可能不再这么详细解释...

Point3_(在core.hpp里)

/*!
  template 3D point class.

  The class defines a point in 3D space. Data type of the point coordinates is specified
  as a template parameter.

  \see cv::Point3i, cv::Point3f and cv::Point3d
*/
template<typename _Tp> class CV_EXPORTS Point3_
{
public:
    typedef _Tp value_type;
    // ... 略去所有函数
    _Tp x, y, z; //< the point coordinates
};

3维的点的定义,多了一个z成员变量.

/*!
  \typedef
  
  shorter aliases for the most popular cv::Point3_<> specializations
*/
typedef Point3_<int> Point3i;
typedef Point3_<float> Point3f;
typedef Point3_<double> Point3d;

注意:此处没有再为Point3_<int>取别名了,可见Point3_<int>不及Point_<int>通用...


Size_(在core.hpp里)

/*!
  The 2D size class

  The class represents the size of a 2D rectangle, image size, matrix size etc.
  Normally, cv::Size ~ cv::Size_<int> is used.
*/
template<typename _Tp> class CV_EXPORTS Size_
{
public:
    typedef _Tp value_type;
    // ...略去所有函数
    _Tp width, height; // the width and the height
};

这个类可以用来表示矩形或者图像的尺寸...它的两个属性是width和height,而不是rows和cols

typedef Size_<int> Size2i;
typedef Size_<float> Size2f;

常用的是int和float

typedef Size2i Size;


Rect_(在core.hpp里)

/*!
  The 2D up-right rectangle class
  
  The class represents a 2D rectangle with coordinates of the specified data type.
  Normally, cv::Rect ~ cv::Rect_<int> is used.
*/
template<typename _Tp> class CV_EXPORTS Rect_
{
public:
    typedef _Tp value_type;
    // 略去所有函数
    _Tp x, y, width, height; //< the top-left corner, as well as width and height of the rectangle
};

这是个矩形类,他有4个成员,分别是矩形的左上角顶点坐标(x,y),宽度width和高度height

显然可以通过宽度和高度计算得到矩形的右下角坐标(x+width,y+height)...

注意:opencv规定了矩形的左边界和上边界属于这个矩形,下边界和右边界不属于这个矩形

x  \leq pt.x < x+width,      y  \leq pt.y < y+height


typedef Rect_<int> Rect;

常用的是int


RotatedRect(在core.hpp里)

/*!
  The rotated 2D rectangle.
  
  The class represents rotated (i.e. not up-right) rectangles on a plane.
  Each rectangle is described by the center point (mass center), length of each side
  (represented by cv::Size2f structure) and the rotation angle in degrees.
*/  
class CV_EXPORTS RotatedRect
{
public:
    // ...略去所有函数
    Point2f center; //< the rectangle mass center
    Size2f size;    //< width and height of the rectangle
    float angle;    //< the rotation angle. When the angle is 0, 90, 180, 270 etc., the rectangle becomes an up-right rectangle. 
};

这个不是模板类了,只支持float

旋转矩形,center是矩形的两条对角线的交点,size.width和size.height分别是矩形的宽和高,angle是旋转角度,所以这个矩形是可以倾斜的,于是我们可以发现up-right retangle其实就是矩形的边平行x轴和y轴的的情况。

关于angle这个参数在我的另一篇博客里细讲 opencv2.0 DataType 实现 ,在1.0版本中对应了Cvbox2D这个结构体...


Range(在core.hpp里)

/*!
   The 2D range class

   This is the class used to specify a continuous subsequence, i.e. part of a contour, or a column span in a matrix.
*/
class CV_EXPORTS Range
{
public:
    // ...略去所有函数
    int start, end;
};

这个也不是模板类
Range类可以理解为区间,可以用于提取矩阵的一行或者一列,成员变量就start和end,分别表示区间的起点和终点

注意:这是一个左闭右开的区间,相信熟悉STL的童鞋,对左闭右开这种写法很习惯了...
[start,end)

Matx(在core.hpp里)

////////////////////////////// Small Matrix ///////////////////////////

template<typename _Tp, int m, int n> class CV_EXPORTS Matx
{
public:
    typedef _Tp value_type;
    typedef Matx<_Tp, MIN(m, n), 1> diag_type;
    typedef Matx<_Tp, m, n> mat_type;
    enum { depth = DataDepth<_Tp>::value, rows = m, cols = n, channels = rows*cols,
           type = CV_MAKETYPE(depth, channels) };
    // ... 
    _Tp val[m*n]; //< matrix elements
};

这个类表示小矩阵,主要是在编译前你可以确定矩阵大小并且矩阵规模较小的情况,仔细看源码的定义,我们发现写库的人直接开了一个静态数组,这个写法感觉略粗糙啊,再吐槽一句吧,c++语法是不建议使用变量来作为数组大小的,可是源码里也直接开m*n了,这样感觉不符合写库的水平啊...

typedef Matx<float, 1, 2> Matx12f;
typedef Matx<double, 1, 2> Matx12d;
typedef Matx<float, 1, 3> Matx13f;
typedef Matx<double, 1, 3> Matx13d;
typedef Matx<float, 1, 4> Matx14f;
typedef Matx<double, 1, 4> Matx14d;
typedef Matx<float, 1, 6> Matx16f;
typedef Matx<double, 1, 6> Matx16d;
    
typedef Matx<float, 2, 1> Matx21f;
typedef Matx<double, 2, 1> Matx21d;
typedef Matx<float, 3, 1> Matx31f;
typedef Matx<double, 3, 1> Matx31d;
typedef Matx<float, 4, 1> Matx41f;
typedef Matx<double, 4, 1> Matx41d;
typedef Matx<float, 6, 1> Matx61f;
typedef Matx<double, 6, 1> Matx61d;

typedef Matx<float, 2, 2> Matx22f;
typedef Matx<double, 2, 2> Matx22d;
typedef Matx<float, 2, 3> Matx23f;
typedef Matx<double, 2, 3> Matx23d;
typedef Matx<float, 3, 2> Matx32f;
typedef Matx<double, 3, 2> Matx32d;
    
typedef Matx<float, 3, 3> Matx33f;
typedef Matx<double, 3, 3> Matx33d;
    
typedef Matx<float, 3, 4> Matx34f;
typedef Matx<double, 3, 4> Matx34d;
typedef Matx<float, 4, 3> Matx43f;
typedef Matx<double, 4, 3> Matx43d;
    
typedef Matx<float, 4, 4> Matx44f;
typedef Matx<double, 4, 4> Matx44d;
typedef Matx<float, 6, 6> Matx66f;
typedef Matx<double, 6, 6> Matx66d;    

这个类常用的类就多了...可以发现主要是float和double...

Vec(在core.hpp里)
/*!
  A short numerical vector.
  
  This template class represents short numerical vectors (of 1, 2, 3, 4 ... elements)
  on which you can perform basic arithmetical operations, access individual elements using [] operator etc.
  The vectors are allocated on stack, as opposite to std::valarray, std::vector, cv::Mat etc.,
  which elements are dynamically allocated in the heap.
  
  The template takes 2 parameters:
  -# _Tp element type
  -# cn the number of elements
  
  In addition to the universal notation like Vec<float, 3>, you can use shorter aliases
  for the most popular specialized variants of Vec, e.g. Vec3f ~ Vec<float, 3>. 
*/ 
template<typename _Tp, int cn> class CV_EXPORTS Vec : public Matx<_Tp, cn, 1>
{
public:
    typedef _Tp value_type;
    enum { depth = DataDepth<_Tp>::value, channels = cn, type = CV_MAKETYPE(depth, channels) };
    // ...
};

这个类继承自Matx,表示了一个cn行1列的矩阵了,注意一个比较蛋疼的问题是,这个分配的空间是在栈区,因为它继承自Matx,而这个写库的人很单纯的开了静态数组,而我们知道静态数组是占用栈空间的,当然如果定义成全局变量就另当别论了,于是又引出一个问题,写库人的本意是这个Vec也是规模很小的,所以千万注意不要开太大,ACMer一般都有经验,普通PC机栈区一般就几M,开个20000以上的就非常危险了。
注意:防止爆栈!!! 如果希望使用大的Vec,那就考虑使用std::vector,然而ACMer知道这玩意的效率是极低的...自己权衡吧

/* \typedef

   Shorter aliases for the most popular specializations of Vec<T,n>
*/
typedef Vec<uchar, 2> Vec2b;
typedef Vec<uchar, 3> Vec3b;
typedef Vec<uchar, 4> Vec4b;

typedef Vec<short, 2> Vec2s;
typedef Vec<short, 3> Vec3s;
typedef Vec<short, 4> Vec4s;

typedef Vec<ushort, 2> Vec2w;
typedef Vec<ushort, 3> Vec3w;
typedef Vec<ushort, 4> Vec4w;    
    
typedef Vec<int, 2> Vec2i;
typedef Vec<int, 3> Vec3i;
typedef Vec<int, 4> Vec4i;
typedef Vec<int, 6> Vec6i;
typedef Vec<int, 8> Vec8i;

typedef Vec<float, 2> Vec2f;
typedef Vec<float, 3> Vec3f;
typedef Vec<float, 4> Vec4f;
typedef Vec<float, 6> Vec6f;

typedef Vec<double, 2> Vec2d;
typedef Vec<double, 3> Vec3d;
typedef Vec<double, 4> Vec4d;
typedef Vec<double, 6> Vec6d;

这个常用的也一大堆,可以看到出现了uchar和ushort,这个是opencv定义的宏,就是unsigned char 和 unsigned short ...

Scalar_(在core.hpp里)
//////////////////////////////// Scalar_ ///////////////////////////////

/*!
   The template scalar class.
   
   This is partially specialized cv::Vec class with the number of elements = 4, i.e. a short vector of four elements.
   Normally, cv::Scalar ~ cv::Scalar_<double> is used. 
*/
template<typename _Tp> class CV_EXPORTS Scalar_ : public Vec<_Tp, 4>
{
public:
    // ... 
};

这个继承自Vec,是一个4行1列的矩阵...
typedef Scalar_<double> Scalar;

Mat(在core.hpp里)
/*!
   The n-dimensional matrix class.
   
   The class represents an n-dimensional dense numerical array that can act as
   a matrix, image, optical flow map, 3-focal tensor etc.
   It is very similar to CvMat and CvMatND types from earlier versions of OpenCV,
   and similarly to those types, the matrix can be multi-channel. It also fully supports ROI mechanism.

*/
class CV_EXPORTS Mat
{
public:
    enum { MAGIC_VAL=0x42FF0000, AUTO_STEP=0, CONTINUOUS_FLAG=CV_MAT_CONT_FLAG, SUBMATRIX_FLAG=CV_SUBMAT_FLAG };

    /*! includes several bit-fields:
         - the magic signature
         - continuity flag
         - depth
         - number of channels
     */
    int flags;
    //! the matrix dimensionality, >= 2
    int dims;
    //! the number of rows and columns or (-1, -1) when the matrix has more than 2 dimensions
    int rows, cols;
    //! pointer to the data
    uchar* data;

    //! pointer to the reference counter;
    // when matrix points to user-allocated data, the pointer is NULL
    int* refcount;
    
    //! helper fields used in locateROI and adjustROI
    uchar* datastart;
    uchar* dataend;
    uchar* datalimit;
    
    //! custom allocator
    MatAllocator* allocator;
    
    struct CV_EXPORTS MSize
    {
        MSize(int* _p);
        Size operator()() const;
        const int& operator[](int i) const;
        int& operator[](int i);
        operator const int*() const;
        bool operator == (const MSize& sz) const;
        bool operator != (const MSize& sz) const;
        
        int* p;
    };
    
    struct CV_EXPORTS MStep
    {
        MStep();
        MStep(size_t s);
        const size_t& operator[](int i) const;
        size_t& operator[](int i);
        operator size_t() const;
        MStep& operator = (size_t s);
        
        size_t* p;
        size_t buf[2];
    protected:
        MStep& operator = (const MStep&);
    };
    
    MSize size;
    MStep step;
};

这个类才是图像处理的神器,当然结构就复杂多了...这是一个表示2维的矩阵,如何表示2维,其实原理很简单,它使用的是1维数组来模拟2维数组...
这里我先介绍一下我知道的一些成员,剩余的以后遇见了再来补充。

先推荐我之前写的一篇博客 OpenCV CvMat 初窥 ,在这里你可以找到关于DEPTH和CN的解释...

在opencv1.0的CvMat里有1个type属性,这个到了2.0就对应了flags属性,经本人观察,这两个属性是一模一样,在前一篇博文里,我介绍了type是怎么编码的...
主要由4部分构成,DEPTH,CN,MAGIC,CONT,其中源码里也有注释...
DEPTH:矩阵数据的类型,目前就7类,参考前一篇博文
CN:通道数,常用的是1,2,3,n
CONT: 图像的连续性,这个是Intel为了利用他们的CPU加速,在存储图像时,往往会往矩阵里添加一些元素来使矩阵元素格式变成4或者8的倍数,便于CPU快速处理
MAGIC:暂时还不知道
其中flags里包含了这4部分信息,编码方式见前一篇博文

dims:这个表示矩阵的维数
rows,cols:矩阵的行数和列数
data:指向数据区域的指针
refcount:这个在opencv1.0的CvMat里也有,供内部使用,其实主要目的是表示这个矩阵实例被引用了多少次,主要方便操作系统来管理内存,当矩阵的引用次数为0时,这个空间会被自动析构,一般来说很多库都会来这样高效的管理内存,这是一种值得我们学习方法
datastart,dataend,datalimit:这个3个指针主要是同来管理ROI(感兴趣区域)的,以后再说.
allocator:这个是个迭代器,具体实现还不清楚,但可以猜测矩阵的有一种类似STL迭代器的遍历方式,大概与这个有关系,以后再说吧

size:是一个内部类,和维度有关系,size的*p在分配空间时,多分配了一个int*的空间,这个是用来存维数的,也就是size[-1]=dims,而对于size[i],i>=0表示第i维的长度
inline Mat::MSize::MSize(int* _p) : p(_p) {}
inline Size Mat::MSize::operator()() const
{
    CV_DbgAssert(p[-1] <= 2);
    return Size(p[1], p[0]);
}
inline const int& Mat::MSize::operator[](int i) const { return p[i]; }
inline int& Mat::MSize::operator[](int i) { return p[i]; }
inline Mat::MSize::operator const int*() const { return p; }

inline bool Mat::MSize::operator == (const MSize& sz) const
{
    int d = p[-1], dsz = sz.p[-1];
    if( d != dsz )
        return false;
    if( d == 2 )
        return p[0] == sz.p[0] && p[1] == sz.p[1];

    for( int i = 0; i < d; i++ )
        if( p[i] != sz.p[i] )
            return false;
    return true;
}

inline bool Mat::MSize::operator != (const MSize& sz) const
{
    return !(*this == sz);
}
注意:size没有默认构造函数,因此Mat的构造函数必须调用size(int*)的构造方法来初始化size,size重载了[]运算符,返回的是引用,所以size[i]完全等价于size.p[i],注意当dims=2时,size[0]和rows的地址是相同的,size[1]和cols的地址也是相同的...

注意:我在书上发现一个误区,书本上说调用Mat的size()方法返回一个Size对象,这是错误的理解,因为Mat根本没有size()方法,实际上是Mat的成员size调用了()运算符,返回了Size对象,这里只能说写书的作者水平有限,没有仔细看Mat的结构

step: 这个类是方便用来寻址的,假设我们要找mat.data[i][j][k],当然不能这样写,因为data是一维数组,所以我们需要将高维地址转换为一维地址,而这个地址就是i*step[0]+j*step[1]+k*step[2],于是可以发现step[i]=step[i+1]*size[i+1] ,然而官方文档告诉我们step[i]>=step[i+1]*size[i+1]...为什么会大于呢?因为矩阵可能不连续存储,因此会在某些维后面补充些空白字节,也就是CONT标记的意义,所以导致了大于号的出现,后面我们会发现我们可以通过这个不等式来做很多事...
inline Mat::MStep::MStep() { p = buf; p[0] = p[1] = 0; }
inline Mat::MStep::MStep(size_t s) { p = buf; p[0] = s; p[1] = 0; }
inline const size_t& Mat::MStep::operator[](int i) const { return p[i]; }
inline size_t& Mat::MStep::operator[](int i) { return p[i]; }
inline Mat::MStep::operator size_t() const
{
    CV_DbgAssert( p == buf );
    return buf[0];
}
inline Mat::MStep& Mat::MStep::operator = (size_t s)
{
    CV_DbgAssert( p == buf );
    buf[0] = s;
    return *this;
}
我们发现里面还有个buf数组,这个是干什么的呢?这个buf只有当dims<=2的时候发挥作用,此时p=buf了...后面会发现opencv中的Mat的dims是不会等于1的...所以只剩dims=0和dims=2的情况了...同理重载了[]运算符,step()返回的是buf[0]...

到此为止!
以后再补充...




猜你喜欢

转载自blog.csdn.net/u012866104/article/details/50808753