OpenCV源码阅读(1)---matx.h---mat类与vec类
matx.h
matx类是opencv中的一个基础类,其位于core模块中,所执行的操作时opencv矩阵和向量的运算。如果熟悉基于matlab的图像处理,那么很容易想到,所有对图像的操作归根结底都是对矩阵的操作。尽管matx类不是opencv最基础的类,但是我认为以此进入图像处理学习和熟悉c++程序是合适的。
1.头文件和基础
#ifndef __OPENCV_CORE_MATX_HPP__
#define __OPENCV_CORE_MATX_HPP__
#ifndef __cplusplus
# error matx.hpp header must be compiled as C++
#endif
#include "opencv2/core/cvdef.h"
#include "opencv2/core/base.hpp"
#include "opencv2/core/traits.hpp"
这是matx类所包含的头文件。其中cvdef.h是opencv的宏定义,定义了基本的cv数据类型等。base.h和traits.h的意义被我忘了,回头补吧。
这也说明了写文档的重要性,不写就忘了。
namespace cv
{
这是表示使用cv这个namespace用’{‘扩起来的范围使用的都是cv
2.矩阵操作定义
struct CV_EXPORTS Matx_AddOp {};
struct CV_EXPORTS Matx_SubOp {};
struct CV_EXPORTS Matx_ScaleOp {};
struct CV_EXPORTS Matx_MulOp {};
struct CV_EXPORTS Matx_DivOp {};
struct CV_EXPORTS Matx_MatMulOp {};
struct CV_EXPORTS Matx_TOp {};
这里定义了矩阵的基本运算,加、减、缩放、乘、除、矩阵乘法、转置,使用的是结构体定义的方式,但是没有具体给出结构体里的内容。注意着只是头文件。继续往下看。
3.matx类声明
template<typename _Tp, int m, int n> class Matx
{
public:
enum { depth = DataType<_Tp>::depth,
rows = m,
cols = n,
channels = rows*cols,
type = CV_MAKETYPE(depth, channels),
shortdim = (m < n ? m : n)
};
typedef _Tp value_type;
typedef Matx<_Tp, m, n> mat_type;
typedef Matx<_Tp, shortdim, 1> diag_type;
这里进入正题,使用了类模板的定义方式。
template<typename _Tp,int m,int n> class Matx
这种写法称为模板操作。
首先是一个枚举数据结构,给matx的公有成员进行赋值,值得注意的是channels定义为矩阵的行乘以列。也就是矩阵元素总数。接下来利用别名机制,定义了value–矩阵值的类型,mat–type,这个指矩阵的类型,包含矩阵值类型,行,列数目。最后是diag_type,数据类型是matx_是一个k行一列的矩阵,k是m,n中较小的值,有可能是矩阵的秩。
3.1 类的构造函数
Matx();
Matx(_Tp v0); //!< 1x1 matrix
Matx(_Tp v0, _Tp v1); //!< 1x2 or 2x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2); //!< 1x3 or 3x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 1x4, 2x2 or 4x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 1x5 or 5x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 1x6, 2x3, 3x2 or 6x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 1x7 or 7x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 1x8, 2x4, 4x2 or 8x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 1x9, 3x3 or 9x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 1x10, 2x5 or 5x2 or 10x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11); //!< 1x12, 2x6, 3x4, 4x3, 6x2 or 12x1 matrix
Matx(_Tp v0, _Tp v1, _Tp v2, _Tp v3,
_Tp v4, _Tp v5, _Tp v6, _Tp v7,
_Tp v8, _Tp v9, _Tp v10, _Tp v11,
_Tp v12, _Tp v13, _Tp v14, _Tp v15); //!< 1x16, 4x4 or 16x1 matrix
explicit Matx(const _Tp* vals); //!< initialize from a plain array
其实在vs2010里看见的是一个非常漂亮的三角形,但是在网页上就不那么漂亮了。这里一共14个构造函数,除去第一个是缺省构造函数,最后一个是利用数组来对矩阵进行复制以外。其他都老老实实用参数对matx类进行复制初始化。
这里说一下explicit关键字,这是用来防止隐式转换发生的。搬运百度百科一个很好的例子
class Test1
{
public:
Test1(int n)
{
num=n;
}//普通构造函数
private:
int num;
};
class Test2
{
public:
explicit Test2(int n)
{
num=n;
}//explicit(显式)构造函数
private:
int num;
};
int main()
{
Test1 t1=12;//隐式调用其构造函数,成功
Test2 t2=12;//编译错误,不能隐式调用其构造函数
Test2 t2(12);//显式调用成功
return 0;
}
也就是说,opencv允许了使用matx mat(val)这样以数组初始化矩阵的方式,但是不允许写成matx mat = val这样的形式。
继续看源码
static Matx all(_Tp alpha);
static Matx zeros();
static Matx ones();
static Matx eye();
static Matx diag(const diag_type& d);
static Matx randu(_Tp a, _Tp b);
static Matx randn(_Tp a, _Tp b);
这里定义了6个函数,函数返回值的类型都是Matx类,并且这都是静态成员函数,代表其可以调用类内的静态数据成员。不能调用非静态数据成员,据说是因为静态成员函数不包含this指针。
这些函数的作用是生成特殊矩阵,如:所有元素全部一样,零矩阵,全部都是1的矩阵,单位阵,对角阵,随机阵。
3.2 类的成员函数—矩阵操作
//! dot product computed with the default precision
_Tp dot(const Matx<_Tp, m, n>& v) const;
//! dot product computed in double-precision arithmetics
double ddot(const Matx<_Tp, m, n>& v) const;
定义了矩阵的点积,其中_Tp是函数模板类型,也就是矩阵元素的类型,在此处属于重载函数,让点积的类型和元素类型相同。dot函数的输入参数是一个矩阵。属于常成员函数。
常成员函数只能读取类的成员变量,而不能修改它。是对数据的保护。
//! convertion to another data type
template<typename T2> operator Matx<T2, m, n>() const;
为什么使用新的模板呢?这是个值得思考的问题需要看这个函数的实现方式来确定
//! change the matrix shape
template<int m1, int n1> Matx<_Tp, m1, n1> reshape() const;
reshape函数,返回值是Matx类型。
//! extract part of the matrix
template<int m1, int n1> Matx<_Tp, m1, n1> get_minor(int i, int j) const;
//! extract the matrix row
Matx<_Tp, 1, n> row(int i) const;
//! extract the matrix column
Matx<_Tp, m, 1> col(int i) const;
//! extract the matrix diagonal
diag_type diag() const;
//! transpose the matrix
Matx<_Tp, n, m> t() const;
上述函数都定义了矩阵的操作,返回类型都是矩阵。唯有diag_type也就是提取对角元素的函数例外,从前面的分析可知,diag_type是矩阵类型的数据,一行,k列,k是m,n中小的。
//! invert the matrix
Matx<_Tp, n, m> inv(int method=DECOMP_LU, bool *p_is_ok = NULL) const;
//! solve linear system
template<int l> Matx<_Tp, n, l> solve(const Matx<_Tp, m, l>& rhs, int flags=DECOMP_LU) const;
Vec<_Tp, n> solve(const Vec<_Tp, m>& rhs, int method) const;
上面的操作时对矩阵求逆和求取线性方程的值,使用了标识符DECOMP_LU,这个应该属于一种宏定义,在头文件中可以找到它的踪迹。
//! multiply two matrices element-wise
Matx<_Tp, m, n> mul(const Matx<_Tp, m, n>& a) const;
//! divide two matrices element-wise
Matx<_Tp, m, n> div(const Matx<_Tp, m, n>& a) const;
这里表达的是矩阵乘除对应元素,相当于matlab中的 .* 和./
//! element access
const _Tp& operator ()(int i, int j) const;
_Tp& operator ()(int i, int j);
//! 1D element access
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
将操作符重载为常成员函数和普通成员函数,操作符的结合数为i和j
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_AddOp);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_SubOp);
template<typename _T2> Matx(const Matx<_Tp, m, n>& a, _T2 alpha, Matx_ScaleOp);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_MulOp);
Matx(const Matx<_Tp, m, n>& a, const Matx<_Tp, m, n>& b, Matx_DivOp);
template<int l> Matx(const Matx<_Tp, m, l>& a, const Matx<_Tp, l, n>& b, Matx_MatMulOp);
Matx(const Matx<_Tp, n, m>& a, Matx_TOp);
这里声明的是矩阵的操作,操作方法是常引用矩阵a,b同时输入一个结构体Matx_*Op但是这个结构体在定义时并没有任何成员,为什么要这样写呢?需要继续查看函数的定义。
3.3 类的数据成员
_Tp val[m*n]; //< matrix elements
};
终于找到你!!!!原来矩阵类的核心就是这个m*n的数组!!!!!
到此为止,整个matx类声明结束了。
matx.h头文件matx类阅读—————20150512未完待续
宏定义——矩阵类型
在matx类的声明之后,是一串宏定义,用于方便的定义各种矩阵。
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;
这里通过给类型名取别名的方式,定义了不同大小,不同数据结构的矩阵型类型名。
vec类
vec类是退化后的matx类,也就是只有一列的矩阵,定义为
template<tempname _Tp,int m> class vec:pulic Matx(_Tp,m,1)
template<typename _Tp, int cn> class Vec : public Matx<_Tp, cn, 1>
{
public:
typedef _Tp value_type;
enum { depth = Matx<_Tp, cn, 1>::depth,
channels = cn,
type = CV_MAKETYPE(depth, channels)
};
//! default constructor
Vec();
Vec(_Tp v0); //!< 1-element vector constructor
Vec(_Tp v0, _Tp v1); //!< 2-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2); //!< 3-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3); //!< 4-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4); //!< 5-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5); //!< 6-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6); //!< 7-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7); //!< 8-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8); //!< 9-element vector constructor
Vec(_Tp v0, _Tp v1, _Tp v2, _Tp v3, _Tp v4, _Tp v5, _Tp v6, _Tp v7, _Tp v8, _Tp v9); //!< 10-element vector constructor
explicit Vec(const _Tp* values);
Vec(const Vec<_Tp, cn>& v);
static Vec all(_Tp alpha);
//! per-element multiplication
Vec mul(const Vec<_Tp, cn>& v) const;
//! conjugation (makes sense for complex numbers and quaternions)
Vec conj() const;
/*!
cross product of the two 3D vectors.
For other dimensionalities the exception is raised
*/
Vec cross(const Vec& v) const;
//! convertion to another data type
template<typename T2> operator Vec<T2, cn>() const;
/*! element access */
const _Tp& operator [](int i) const;
_Tp& operator[](int i);
const _Tp& operator ()(int i) const;
_Tp& operator ()(int i);
Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_AddOp);
Vec(const Matx<_Tp, cn, 1>& a, const Matx<_Tp, cn, 1>& b, Matx_SubOp);
template<typename _T2> Vec(const Matx<_Tp, cn, 1>& a, _T2 alpha, Matx_ScaleOp);
};
/* \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;
/*!
traits
*/
template<typename _Tp, int cn> class DataType< Vec<_Tp, cn> >
{
public:
typedef Vec<_Tp, cn> value_type;
typedef Vec<typename DataType<_Tp>::work_type, cn> work_type;
typedef _Tp channel_type;
typedef value_type vec_type;
enum { generic_type = 0,
depth = DataType<channel_type>::depth,
channels = cn,
fmt = DataType<channel_type>::fmt + ((channels - 1) << 8),
type = CV_MAKETYPE(depth, channels)
};
};
/*!
Comma-separated Vec Initializer
*/
template<typename _Tp, int m> class VecCommaInitializer : public MatxCommaInitializer<_Tp, m, 1>
{
public:
VecCommaInitializer(Vec<_Tp, m>* _vec);
template<typename T2> VecCommaInitializer<_Tp, m>& operator , (T2 val);
Vec<_Tp, m> operator *() const;
};
/*!
Utility methods
*/
template<typename _Tp, int cn> static Vec<_Tp, cn> normalize(const Vec<_Tp, cn>& v);
这完全就是matx类的翻版。具体解释参考matx类。
版权声明:本文为博主原创文章,未经博主允许不得转载。
OpenCV源码阅读(1)---matx.h---mat类与vec类的更多相关文章
- OpenCV源码阅读(3)---matx.h---学习心得
在.h文件里定义类,可以通过内联函数的方法完成类基础函数的实现,这样就不需要额外写.cpp文件来写类的内容. 对于操作符重载,可以使用返回应用的方式减小内存开销 _Tp& someclass: ...
- OpenCV源码阅读(2)---matx.h---函数的内联实现
外部矩阵计算函数 namespace internal { template<typename _Tp, int m> struct Matx_DetOp { double operato ...
- opencv源码阅读之——iOS的两条接口UIImageToMat()和MatToUIImage()
本文为作者原创,未经允许不得转载:原文由作者发表在博客园: http://www.cnblogs.com/panxiaochun/p/5387743.html 在ios下开发基于opencv的程序时经 ...
- OpenCV源码阅读(3)---base.hpp
base.h处于core模块中,是OpenCV的核心类.其作用是定义了OpenCV的基本错误类型,在程序运行出现错误是抛出错误,防止数据溢出.总而言之,其功能主要是考虑程序的健壮性. 头文件 #ifn ...
- 【opencv 源码剖析】 四、 Mat的赋值构造函数 和 拷贝构造函数
1.赋值构造函数 右值引用 inline Mat& Mat::operator = (Mat&& m) { if (this == &m) return *this; ...
- JDK源码阅读(3):AbstractStringBuilder、StringBuffer、StringBuilder类阅读笔记
AbstractStringBuilder abstract class AbstractStringBuilder implements Appendable, CharSequence{ ... ...
- 16 BasicHashTable基本哈希表类(三)——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
- 15 BasicHashTable基本哈希表类(二)——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
- 14 BasicHashTable基本哈希表类(一)——Live555源码阅读(一)基本组件类
这是Live555源码阅读的第一部分,包括了时间类,延时队列类,处理程序描述类,哈希表类这四个大类. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/oloroso ...
随机推荐
- 一,XAML基础
RuntimeNameProperty特性:为什么<Grid x:Name="grid1"></Grid>等价于<Grid Name="gr ...
- C# 缓存学习总结
昨天整理了一下缓存的基本用法,和缓存依赖类 CacheDependency类的使用,今天整理一下缓存的数据库依赖类SqlCacheDependency 1.数据库依赖类SqlCacheDependen ...
- static方法不能直接访问类内的非static变量和不能调用this,super语句分析
大家都知道在static方法中,不能访问类内非static成员变量和方法.可是原因是什么呢? 这首先要从static方法的特性说起.static方法,即类的静态成员经常被称为"成员变量&qu ...
- ios技术面试题
1.Difference between shallow copy and deep copy? 浅复制 只拷贝地址 不拷贝地址指向的对象 深复制 拷贝地址 并且指向拷贝的新对象 2.What is ...
- 【BZOJ 1090】[SCOI2003]字符串折叠
Description 折 叠的定义如下: 1. 一个字符串可以看成它自身的折叠.记作S S 2. X(S)是X(X>1)个S连接在一起的串的折叠.记作X(S) SSSS…S(X个S). ...
- C#系统缓存全解析
原文:http://blog.csdn.net/wyxhd2008/article/details/8076105 目录(?)[-] 系统缓存的概述 页面输出缓存 页面局部缓存 文件缓存依赖 数据库缓 ...
- WebApi参数传递总结
在WebAPI中,请求主体(HttpContent)只能被读取一次,不被缓存,只能向前读取的流. 举例子说明: 1. 请求地址:/?id=123&name=bob 服务端方法: void Ac ...
- 在ASP.NET MVC应用程序中实现Server.Transfer()类似的功能
在ASP.NET MVC应用程序中,如果使用Server.Transfer()方法希望将请求转发到其它路径或者Http处理程序进行处理,都会引发“为xxx执行子请求时出错”的HttpException ...
- android禁止ScrollView自动滚动
当Scrollview嵌套listview,或者子View的内容过多时,当内容加载完成后,ScrollView中内容的长度会发生改变,ScrollView会自动往下滚动,解决办法:在ScollView ...
- MyEclipse2015破解版_MyEclipse 2015 stable 2.0 稳定版 破解日志
前言:在MyEclipse 2015 Stable 1.0下载安装破解日志(http://www.cnblogs.com/wql025/p/5161979.html)一文中,笔者主要讲述了该版本的破解 ...