- 文章转载自新浪博客:http://blog.sina.com.cn/s/blog_7908e1290101i97z.html
-
综述:
- OpenCV有针对矩阵操作的C语言函数. 许多其他方法提供了更加方便的C++接口,其效率与OpenCV一样.
- OpenCV将向量作为1维矩阵处理.
- 矩阵按行存储,每行有4字节的校整.
- //由于opencv的矩阵式一位数组或者一位指针,所以我们只能利用opencv的函数对矩阵元素进行操作(当然这样也是最安全的做法,- -!太不习惯了)
- 分配矩阵空间:
CvMat* cvCreateMat(int rows, int cols, int type); type: 矩阵元素类型. 格式为CV_(S|U|F)C. 例如: CV_8UC1 表示8位无符号单通道矩阵, CV_32SC2表示32位有符号双通道矩阵. 例程: CvMat* M = cvCreateMat(4,4,CV_32FC1)//这个函数用来初始化Mat,不初始化虽然是会报warrying,但是运行时会报错,由于Mat和IplImage的类型不太一样,所以做两者之间转换的时候想改变数据类型很难(大概可以先转换矩阵类型,再转换数据类型,这就麻烦了,还没找到好方法),还需要注意这个分配空间并不管理数据的初始化,最好利用cvSet对数据进行初始化。
-
- 释放矩阵空间:
CvMat* M = cvCreateMat(4,4,CV_32FC1); cvReleaseMat(&M);//这个别忘了用就是了
- 复制矩阵:
CvMat* M1 = cvCreateMat(4,4,CV_32FC1); CvMat* M2; M2=cvCloneMat(M1);
- 初始化矩阵:
double a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }; CvMat Ma=cvMat(3, 4, CV_64FC1, a); 另一种方法:
CvMat Ma; cvInitMatHeader(&Ma, 3, 4, CV_64FC1, a);
- 初始化矩阵为单位阵:
CvMat* M = cvCreateMat(4,4,CV_32FC1); cvSetIdentity(M); // 这里似乎有问题。
//这个函数可以初始化对角线上的元素,这个是单位阵,不是所有元素都赋1,这个函数需要第二个函数,虽然有默认值,但是这个变量和我之前的理解有点不对,也没有实验,贴个原型吧:
void cvSetIdentity( CvArr* mat, CvScalar value=cvRealScalar(1) );这里的cvRealScalar(1)是个强制类型转换。
-
存取矩阵元素
- 假设需要存取一个2维浮点矩阵的第(i,j)个元素.
- 间接存取矩阵元素:
-
cvmSet(M,i,j,2.0); // Set M(i,j) t = cvmGet(M,i,j); // Get M(i,j)
- 直接存取,假设使用4-字节校正:
CvMat* M = cvCreateMat(4,4,CV_32FC1); int n = M->cols; float *data = M->data.fl; data[i*n+j] = 3.0;
- 直接存取,校正字节任意:
CvMat* M = cvCreateMat(4,4,CV_32FC1); int step = M->step/sizeof(float); float *data = M->data.fl;//这个也是Mat和IplImage的区别,Mat的data是union类型,里面是五个不同类型的指针,根据你存储的类型选择相同类型的指针;而IplImage的imagedata就直接存储数据了。 (data+i*step)[j] = 3.0;
- 直接存取一个初始化的矩阵元素:
double a[16]; CvMat Ma = cvMat(3, 4, CV_64FC1, a); a[i*4+j] = 2.0; // Ma(i,j)=2.0;
-
矩阵/向量操作
- 矩阵-矩阵操作:
CvMat *Ma, *Mb, *Mc; cvAdd(Ma, Mb, Mc); // Ma+Mb -> Mc cvSub(Ma, Mb, Mc); // Ma-Mb -> Mc cvMatMul(Ma, Mb, Mc); // Ma*Mb -> Mc//从前几天看到的一些技巧,我感觉这个几个函数不是很好,没有返回值,不能嵌套调用,想完成三个矩阵的相乘,还需要临时变量,比如恢复SVD的时候。
- 按元素的矩阵操作:
CvMat *Ma, *Mb, *Mc; cvMul(Ma, Mb, Mc); // Ma.*Mb -> Mc cvDiv(Ma, Mb, Mc); // Ma./Mb -> Mc cvAddS(Ma, cvScalar(-10.0), Mc); // Ma.-10 -> Mc
- 向量乘积:
double va[] = {1, 2, 3}; double vb[] = {0, 0, 1}; double vc[3]; CvMat Va=cvMat(3, 1, CV_64FC1, va); CvMat Vb=cvMat(3, 1, CV_64FC1, vb); CvMat Vc=cvMat(3, 1, CV_64FC1, vc); double res=cvDotProduct(&Va,&Vb); // 点乘: Va . Vb -> res cvCrossProduct(&Va, &Vb, &Vc); // 向量积: Va x Vb -> Vc end{verbatim}
注意 Va, Vb, Vc 在向量积中向量元素个数须相同.
- 单矩阵操作:
CvMat *Ma, *Mb; cvTranspose(Ma, Mb); // transpose(Ma) -> Mb (不能对自身进行转置) CvScalar t = cvTrace(Ma); // trace(Ma) -> t.val[0] double d = cvDet(Ma); // det(Ma) -> d cvInvert(Ma, Mb); // inv(Ma) -> Mb
- 非齐次线性系统求解:
CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* x = cvCreateMat(3,1,CV_32FC1); CvMat* b = cvCreateMat(3,1,CV_32FC1); cvSolve(&A, &b, &x); // solve (Ax=b) for x
- 特征值分析(针对对称矩阵):
CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* E = cvCreateMat(3,3,CV_32FC1); CvMat* l = cvCreateMat(3,1,CV_32FC1); cvEigenVV(&A, &E, &l); // l = A的特征值 (降序排列) // E = 对应的特征向量 (每行)
- 奇异值分解SVD:
CvMat* A = cvCreateMat(3,3,CV_32FC1); CvMat* U = cvCreateMat(3,3,CV_32FC1); CvMat* D = cvCreateMat(3,3,CV_32FC1); CvMat* V = cvCreateMat(3,3,CV_32FC1); cvSVD(A, D, U, V, CV_SVD_U_T|CV_SVD_V_T); // A = U D V^T
标号使得 U 和 V 返回时被转置(若没有转置标号,则有问题不成功!!!).//这个函数解释比较少,首先这个函数不能接受IplImage类型的输入变量,其次必须是浮点型,原文中这个问题,我没有遇到,我使用时最后一个参数用的是默认值0。
//
目标
- Mat A, C; //仅创建了头部
- A = imread(argv[1], CV_LOAD_IMAGE_COLOR); //在此我们知道使用的方法(分配矩阵)
- Mat B(A); //使用拷贝构造函数
- C = A; //赋值运算符
- <p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat D (A, Rect(10, 10, 100, 100) );<em> // 用矩形界定</em></font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat E = A(Range:all(), Range(1,3)); <em>// 用行和列来界定</em></font></p>
现在,你可能会问是否矩阵的本身可以属于多个Mat对象在不再需要时负责清理数据。简短的回答是:最后一个使用它的对象。这对于使用引用计数的机制,每当有人复制Mat对象的头,矩阵的计数器被增加。每当一个头被清除,此计数器被下调。当该计数器变为零,矩阵也就被释放了。因为有时会仍然也要复制矩阵的本身,存在着 clone() 或 copyTo() 函数。
- <p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat F = A.clone();</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat G;</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">A.copyTo(G);</font></p>
现在 modifyingForGwill 不会影响由 theMatheader 指出的矩阵。你要记得从所有的是:
• Mat()构造函数
Mat M(2,2, CV_8UC3, Scalar(0,0,255));
cout << "M = " << endl << " " << M << endl << endl;
CV_ [每一项的位数] [有符号或无符号] [类型前缀] C [通道数]
例如,CV_8UC3 意味着我们使用那些长的 8 位无符号的 char 类型和每个像素都有三个项目的这三个通道的形成。这是预定义的四个通道数字。Scalar 是四个元素短向量。指定此和可以初始化所有矩阵点与自定义的值。但是如果你需要更多您可以创建与上部宏和频道号码放在括号中,您可以看到下面的类型。
- <p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">int sz[3] = {2,2,2};</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat L(3,sz,CV_8UC(1),Scalar::all(0));</font></p>
上例为我们展示了如何创建一个二维以上的矩阵。首先指定其维度数,然后传入一个包含了尺寸每个维度信息的指针,其他都保持不变。
•为一个已经存在的IplImage创建一个头:
IplImage* img = cvLoadImage("greatwave.png", 1);
Mat mtx(img); // 转换 IplImage*-> Mat
• Create()函数:
M.create(4,4, CV_8UC(2));
cout << "M = "<< endl << " " << M << endl << endl;
你不能通过这个构造来初始化矩阵中的数值。它只会在新的居住尺寸与旧的矩阵尺寸不合时重新分配矩阵的数据空间。
• MATLAB风格的初始化函数:zeros(), ones(),
:eyes().指定使用的尺寸和数据类型
- <p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat E = Mat::eye(4, 4, CV_64F);</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">cout << "E = " << endl << " " << E << endl << endl;</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat O = Mat::ones(2, 2, CV_32F);</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">cout << "O = " << endl << " " << O << endl << endl;</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">Mat Z = Mat::zeros(3,3, CV_8UC1);</font></p><p style="margin-top: 5px; margin-bottom: 5px; "><font size="2">cout << "Z = " << endl << " " << Z << endl << endl;</font></p>
•对于小的矩阵来说你可以使用逗号隔开的初始化函数:
Mat C = (Mat_<double>(3,3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
cout << "C = " << endl << " " << C << endl << endl;
•为一个已有的Mat对象创建一个新的头然后clone()或者copyTo()这个头.
Mat RowClone = C.row(1).clone();
cout << "RowClone = " << endl << " " << RowClone << endl << endl;
注意:你可以通过用randu()函数产生的随机值来填充矩阵。你需要给定一个上限和下限来确保随机值在你期望的范围内:
Mat R = Mat(3, 2, CV_8UC3);
randu(R, Scalar::all(0), Scalar::all(255));
在上一个例子中你可以看到默认的格式选项。尽管如此,OpenCV允许你在符合以下规则的同时格式化你的输出:
• 默认
cout << "R (default) = " << endl << R << endl << endl;
• Python
cout << "R (python) = " << endl << format(R,"python") << endl << endl;
• Comma separated values (CSV)
cout << "R (csv) = " << endl << format(R,"csv" ) << endl << endl;
• Numpy
cout << "R (numpy) = " << endl << format(R,"numpy" ) << endl << endl;
• C
cout << "R (c) = " << endl << format(R,"C" ) << endl << endl;
OpenCV 通过<<操作符也为其他常用OpenCV数据结构提供打印输出的支持,如:
• 2D 点
Point2f P(5, 1);
cout << "Point (2D) = " << P << endl << endl;
• 3D 点
Point3f P3f(2, 6, 7);
cout << "Point (3D) = " << P3f << endl << endl;
• std::vector通过 cv::Mat
vector<float> v;
v.push_back( (float)CV_PI); v.push_back(2); v.push_back(3.01f);
cout << "Vector of floats via Mat = " << Mat(v) << endl << endl;
•点的std::vector
vector<Point2f> vPoints(20);
for (size_t E = 0; E < vPoints.size(); ++E)
vPoints[E] = Point2f((float)(E*5), (float)(E % 7));
cout << "A vector of 2D Points = " << vPoints << endl << endl;
这里大多数的例程都是在一个小控制台程序里运行。你可以在这里下载或是在cpp示例文件夹下找到。
你可以在YouTube.上找到一个快速的实例演示
Mat::~MatMat的析构函数。
C++: Mat::~Mat()
析构函数调用Mat::release()。
Mat::operator =提供矩阵赋值操作。
C++: Mat& Mat::operator=(const Mat& m)
C++: Mat& Mat::operator=(const MatExpr_Base& expr)
C++: Mat& Mat::operator=(const Scalar& s)
参数:
m – 被赋值的右侧的矩阵。 矩阵的赋值是一个复杂度为O(1) 的操作。 这就意味着没有数据段复制并且有数量的递增两矩阵将使用同一引用计数器。在给矩阵赋新数据之前先由Mat::release()释放引用。
expr –被赋值的矩阵表达式对象。 作为第一种赋值方式的逆操作第二种形式可以被重新用到具有适当大小和尺寸的已分配空间的矩阵上以适应表达式的结果。矩阵表达式扩展得到的实函数将自动处理这个分配过程。例如:
C=A+B 扩展成add(A, B, C) , andadd() 要当心C重新分配数据的操作。.
s – 标量赋值给每一个矩阵元,矩阵的大小和类型将不会改变。有现成的赋值运算符。由于他们各不相同请阅读运算符参数说明。
Mat::operator MatExpr提供一种Mat-to-MatExpr转换运算符
C++: Mat::operator MatExpr_<Mat, Mat>() const
转换运算符不能显示调用而是由矩阵表达式引擎(Matrix Expression engine)内部调用The cast operator should not be called explicitly. It is used internally by the Matrix Expressions engine.
Mat::row创建一个指定行数的矩阵头。.
C++: Mat Mat::row(int i) const
参数:
i – 一个0基的行索引.
该方法创建一个具有指定了行数的新矩阵头的矩阵并返回它。这是一个复杂度为O(1) 的操作,无须考虑矩阵的尺寸。新矩阵和原矩阵共享一份基础数据。这是一个典型基本矩阵处理操作的例子, axpy是LU和许多其它算法都使用的一个函数
inline void matrix_axpy(Mat& A, int i, int j, double alpha)
{
A.row(i) += A.row(j)*alpha;
}
Note:在当前实现中,下面的代码不会无法按预期的效果工作:
Mat A ;
...
A.row(i) = A.row(j) ;/ /不起作用
发生这种情况是因为 A.row(i) 形成临时矩阵头进一步分配给另一个矩阵头。请记住,每个操作复杂度为O(1),即没有复制任何数据。因此,如果你预期第 j行被复制到第 i行,那么上述赋值不成立。要做到这一点,应该把这种简单的赋值转换到表达式中或使用 Mat::copyTo() 方法:
Mat A ;
...
/ / 可行,但看上去有点目的不明确。
A.row(i) = A.row(j) + 0;
/ / 这是有点儿长,但这是推荐的方法。
A.row(j).copyTo(A.row(i)) ;
Mat::col创建一个具有指定了矩阵头中列数这个参数的矩阵
C++: Mat Mat::col(int j) const
参数:
j –一个0基(从0开始)的列索引
该方法创建一个具有指定了矩阵头中列数这个参数的新矩阵并作为函数返回值。这是一种复杂度为O(1)的操作,不用考虑矩阵的尺寸大小。新矩阵和原始矩阵共享一份基础数据。参看Mat::row()说明信息。
Mat::rowRange为指定的行span创建一个新的矩阵头。
C++: Mat Mat::rowRange(int startrow, int endrow) const
C++: Mat Mat::rowRange(const Range& r) const
参数:
startrow – 一个包容性的0基(从0开始)的行span起始索引.。
endrow – 一个0基的独占性的行span.终止索引。
r – Range 结构包含着起始和终止的索引值。该方法给矩阵指定的行span创建了新的头。 与Mat::row() 和 Mat::col()相类似这是一个复杂度为O(1)的操作。
Mat::colRange为指定的行span创建一个矩阵头。
C++: Mat Mat::colRange(int startcol, int endcol) const
C++: Mat Mat::colRange(const Range& r) const
参数:
startcol – 一个包容性的0基(从0开始)的span列起始索引。
endcol –一个0基的独占性的列span.终止索引。
r –Range 结构包含着起始和终止的索引值。该方法给矩阵指定的列span创建了新的头。 与Mat::row() 和 Mat::col()相类似这是一个复杂度为O(1)的操作。
Mat::diag提取或创建矩阵对角线。
C++: Mat Mat::diag(int d) const
C++: static Mat Mat::diag(const Mat& matD)
参数:
d – 对角线的索引值,可以是以下的值:
– d=0 是主对角线
– d>0表示下半部的对角线。例如:d=1对角线是紧挨着住对角线并位于矩阵下方。
– d<0表示来自矩阵上半部的对角线。例如:d= 1表示对角线被设置在对角线的上方并紧挨着。
matD – 单列用于形成矩阵对角线的列。
该方法为指定的矩阵创建一个新的头。然后新矩阵被分割为单独的列矩阵。类似于Mat::row() 和Mat::col() ,它是复杂度为O(1)操作。
Mat::clone创建一个数组及其基础数据的完整副本。
C++: Mat Mat::clone() const
该方法创建了一个完整的数组副本。原始的step[]不会被考虑在内的。因此数组的副本是一占用total()*elemSize()字节的连续阵列。
Mat::copyTo把矩阵复制到另一个矩阵中。
C++: void Mat::copyTo(OutputArray m) const
C++: void Mat::copyTo(OutputArray m, InputArray mask) const
参数:
m – 目标矩阵。如果它的尺寸和类型不正确,在操作之前会重新分配。
mask – 操作掩码。它的非零元素表示矩阵中某个要被复制。
该方法把矩阵的复制到另一个新的矩阵中在复制之前该方法会调用
m.create(this->size(), this->type);
因此,目标矩阵会在必要的情况下重新分配
尽管m.copyTo(m) works flawlessly,该函数并不处理源矩阵和目标矩阵之间有重叠的部分的情况。当操作掩码指定以及上述的Mat::create重新分配矩阵,新分配的矩阵在数据复制到里面之前全都被初始化为0。
Mat::convertTo在缩放或不缩放的情况下转换为另一种数据类型。
C++:
void Mat::convertTo(OutputArray m,int rtype,double alpha=1,double beta=0)const
参数:
m – 目标矩阵。如果它的尺寸和类型不正确,在操作之前会重新分配。
rtype – 要求是目标矩阵的类型,或者在当前通道数与源矩阵通道数相同的情况下的depth。如果rtype 为负,目标矩阵与源矩阵类型相同。
beta – 可选的delta加到缩放值中去。
该方法将源像素值转化为目标类型saturate_cast<> 要放在最后以避免溢出
m( x;y) = saturate_cast < rType > ( α*( *this)( x;y) +β)
Mat::assignTo提供了一个convertTo的功能形式。
C++: void Mat::assignTo(Mat& m, int type=-1 ) const
Parameters
m – 目标阵列。
type – 要求是目标阵列depth或-1(如果阵列的类型和源矩阵类型相同)
这是一个 internally 使用的由 Matrix Expressions引擎调用的方法。
Mat::setTo将阵列中所有的或部分的元素设置为指定的值。
C++: Mat& Mat::setTo(const Scalar& s, InputArray mask=noArray())
参数:
s – 把标量赋给阵列并转化到阵列的实际类型。
mask – 与 *this尺寸相同的操作掩码。这是Mat::operator=(const Scalar& s)运算符的一个高级变量。
Mat::reshape在无需复制数据的前提下改变2D矩阵的形状和通道数或其中之一。
C++: Mat Mat::reshape(int cn, int rows=0) const
参数:
cn – 新的通道数。若cn=0,那么通道数就保持不变。
rows –新的行数。 若rows = 0, 那么行数保持不变。
该方法为*this元素创建新的矩阵头。这新的矩阵头尺寸和通道数或其中之一发生改变,在以下的情况任意组合都是有可能的:
ü 新的矩阵没有新增或减少元素。通常,rows*cols*channels()在转换过程中保持一致。.
ü 无数据的复制。也就是说,这是一个复杂度为 O(1)的操作。通常,如果该操作改变行数或透过其他方式改变元素行索引,那么矩阵必定是连续的。参见Mat::isContinuous()。
例如,有一存储了STL向量的三维点集,你想用3xN的矩阵来完成下面的操作:
std::vector<Point3f> vec;
...
Mat pointMat = Mat(vec). //把向量转化成Mat, 复杂度为O(1)的运算
reshape(1). // 从Nx1的3通道矩阵得出Nx3 的单通道矩阵
//同样是复杂度为O(1)的运算
t(); // 最后转置Nx3 的矩阵
//这个过程要复制所有的元素
Mat::t转置矩阵。.
C++: MatExpr Mat::t() const
该方法通过矩阵表达式(matrix expression)实现矩阵的转置The method performs matrix transposition by means of matrix expressions. 它并未真正完成了转置但却返回一个临时的可以进一步用在更复杂的矩阵表达式中或赋给一个矩阵的转置矩阵对象:
Mat A1 = A + Mat::eye(A.size(), A.type)*lambda;
Mat C = A1.t()*A1; //计算(A + lambda*I)^t * (A + lamda*I).
Mat::inv反转矩阵
C++: MatExpr Mat::inv(int method=DECOMP_LU) const
参数:
method – 反转矩阵的方法。有以下几种可能的值:
– DECOMP_LU是 LU 分解一定不能是单数的。
– DECOMP_CHOLESKY 是 Cholesky LLT只适用于对称正矩阵的分解。该类型在处理大的矩阵时的速度是LU的两倍左右。
– DECOMP_SVD是 SVD 分解。如果矩阵是单数或甚至不是2维,函数就会计算伪反转矩阵。
该方法执行矩阵的反转矩阵表达。这意味着该方法返回一个临时矩阵反转对象并可进一步用于更复杂的矩阵表达式的中或分配给一个矩阵。
Mat::mul执行两个矩阵按元素相乘或这两个矩阵的除法。
C++: MatExpr Mat::mul(InputArray m, double scale=1) const
参数:
m – 与*this具有相同类型和大小的矩阵,或矩阵表达式。
scale – 可选缩放系数。
该方法返回一个用可选的缩放比率编码了每个元素的数组乘法的临时的对象。 注意:这不是一个对应“*”运算符的简单的矩阵乘法。.
例::
Mat C = A.mul(5/B); // 等价于divide(A, B, C, 5)
Mat::cross计算3元素向量的一个叉乘积。
C++: Mat Mat::cross(InputArray m) const
参数:
m –另一个叉乘操作对象。
该方法计算了两个3元素向量的叉乘的积被操作向量必须是3元素浮点型的具有相同形状和尺寸的向量。结果也是一语被操作对象的具有相同形状和大小的浮点型3元素向量。
Mat::dot计算两向量的点乘。
C++: double Mat::dot(InputArray m) const
参数:
m –另一个点积操作对象。
方法计算两个矩阵的点积。如果矩阵不单列或单行的向量,用顶部到底部从左到右扫描次序将它们视为 1 D向量。这些向量必须具有相同的大小和类型。如果矩阵有多个通道,从所有通道得到的点积会被加在一起。
Mat::zeros返回指定的大小和类型的零数组。
C++: static MatExpr Mat::zeros(int rows, int cols, int type)
C++: static MatExpr Mat::zeros(Size size, int type)
C++: static MatExpr Mat::zeros(int ndims, const int* sizes, int type)
参数
ndims – 数组的维数。
rows–行数。
cols –列数。
size–替代矩阵大小规格Size(cols, rows)的方法。
sizes– 指定数组的形状的整数数组。
type– 创建的矩阵的类型。
该方法返回一个 Matlab 式的零数组初始值设定项。它可以用于快速形成一个常数数组作为函数参数,作为矩阵的表达式或矩阵初始值设定项的一部分。
Mat A;
A = Mat::zeros (3,3,CV_32F);
在上面的示例中,只要A不是 3 x 3浮点矩阵它就会被分配新的矩阵。否则为现有的
矩阵 A填充零。
Mat::ones返回一个指定的大小和类型的全为1的数组。
C++: static MatExpr Mat::ones(int rows, int cols, int type)
C++: static MatExpr Mat::ones(Size size, int type)
C++: static MatExpr Mat::ones(int ndims, const int* sizes, int type)
参数:
ndims –数组的维数。
rows –行数。.
cols –列数。
size –替代矩阵大小规格Size(cols, rows)的方法。
sizes –指定数组的形状的整数数组。
type –创建的矩阵的类型。
该方法返回一个 Matlab 样式 1 的数组初始值设定项,类似Mat::zeros()。请注意,这种方法中你可以使用任意一个值和Matlab 语法初始化数组如下:
Mat A = Mat::ones (100,100,CV_8U) * 3 ;/ / 使100 x 100 矩阵里充满 3。
上述操作不会形成一个 100 x 100 1 的矩阵,然后乘以 3。相反,它只是记住
缩放因子(在本例中 3)在实际调用矩阵初始值设定项时使用它。