opencv矩阵操作.docx
《opencv矩阵操作.docx》由会员分享,可在线阅读,更多相关《opencv矩阵操作.docx(16页珍藏版)》请在冰豆网上搜索。
opencv矩阵操作
通用矩阵乘法
voidcvGEMM(constCvArr*src1,constCvArr*src2,doublealpha,
constCvArr*src3,doublebeta,CvArr*dst,inttABC=0);
#definecvMatMulAdd(src1,src2,src3,dst)cvGEMM(src1,src2,1,src3,1,dst,0)
#definecvMatMul(src1,src2,dst)cvMatMulAdd(src1,src2,0,dst)
src1
第一输入数组
src2
第二输入数组
src3
第三输入数组(偏移量),如果没有偏移量,可以为空(NULL)。
dst
输出数组
tABC
T操作标志,可以是0或者下面列举的值的组合:
CV_GEMM_A_T-转置src1
CV_GEMM_B_T-转置src2
CV_GEMM_C_T-转置src3
例如,CV_GEMM_A_T+CV_GEMM_C_T对应
alpha*src1T*src2+beta*src3T
函数cvGEMM执行通用矩阵乘法:
dst=alpha*op(src1)*op(src2)+beta*op(src3),这里op(X)是X或者XT
所有的矩阵应该有相同的数据类型和协调的矩阵大小。
支持实数浮点矩阵或者复数浮点矩阵。
[编辑]
Transform
对数组每一个元素执行矩阵变换
voidcvTransform(constCvArr*src,CvArr*dst,constCvMat*transmat,constCvMat*shiftvec=NULL);
src
输入数组
dst
输出数组
transmat
变换矩阵
shiftvec
可选偏移向量
函数cvTransform对数组src每一个元素执行矩阵变换并将结果存储到dst:
dst(I)=transmat*src(I)+shiftvec
或者
dst(I)k=sumj(transmat(k,j)*src(I)j)+shiftvec(k)
N-通道数组src的每一个元素都被视为一个N元向量,使用一个M×N的变换矩阵transmat和偏移向量shiftvec把它变换到一个M-通道的数组dst的一个元素中。
这里可以选择将偏移向量shiftvec嵌入到transmat中。
这样的话transmat应该是M×N+1的矩阵,并且最右边的一列被看作是偏移向量。
输入数组和输出数组应该有相同的位深(depth)和同样的大小或者ROI大小。
transmat和shiftvec应该是实数浮点矩阵。
该函数可以用来进行ND点集的几何变换,任意的线性颜色空间变换,通道转换等。
MulTransposed
计算数组和数组的转置的乘积
voidcvMulTransposed(constCvArr*src,CvArr*dst,intorder,constCvArr*delta=NULL);
src
输入矩阵
dst
目标矩阵
order
乘法顺序
delta
一个可选数组,在乘法之前从src中减去该数组。
函数cvMulTransposed计算src和它的转置的乘积。
函数求值公式:
如果order=0
dst=(src-delta)*(src-delta)T
否则
dst=(src-delta)T*(src-delta)
[编辑]
Trace
返回矩阵的迹
CvScalarcvTrace(constCvArr*mat);
mat
输入矩阵
函数cvTrace返回矩阵mat的对角线元素的和。
tr(src)=
∑
mat(i,i)
i
[编辑]
Transpose
矩阵的转置
voidcvTranspose(constCvArr*src,CvArr*dst);
#definecvTcvTranspose
src
输入矩阵
dst
目标矩阵
函数cvTranspose对矩阵src求转置:
dst(i,j)=src(j,i)
注意,假设是复数矩阵不会求得复数的共轭。
共轭应该是独立的:
查看的cvXorS例子代码。
[编辑]
Det
返回矩阵的行列式值
doublecvDet(constCvArr*mat);
mat
输入矩阵
函数cvDet返回方阵mat的行列式值。
对小矩阵直接计算,对大矩阵用高斯(GAUSSIAN)消去法。
对于对称正定(positive-determined)矩阵也可以用SVD函数来求,U=V=NULL,然后用w的对角线元素的乘积来计算行列式。
[编辑]
Invert
查找矩阵的逆矩阵或伪逆矩阵
doublecvInvert(constCvArr*src,CvArr*dst,intmethod=CV_LU);
#definecvInvcvInvert
src
输入矩阵
dst
目标矩阵
method
求逆方法:
CV_LU-最佳主元选取的高斯消除法
CV_SVD-奇异值分解法(SVD)
CV_SVD_SYM-正定对称矩阵的SVD方法
函数cvInvert对矩阵src求逆并将结果存储到dst。
如果是LU方法该函数返回src的行列式值(src必须是方阵)。
如果是0,矩阵不求逆,dst用0填充。
如果SVD方法该函数返回src的条件数的倒数(最小奇异值和最大奇异值的比值),如果src全为0则返回0。
如果src是奇异的,SVD方法计算一个伪逆矩阵。
Solve
求解线性系统或者最小二乘法问题
intcvSolve(constCvArr*src1,constCvArr*src2,CvArr*dst,intmethod=CV_LU);
src1
输入矩阵
src2
线性系统的右部
dst
输出解答
method
解决方法(矩阵求逆):
CV_LU-最佳主元选取的高斯消除法
CV_SVD-奇异值分解法(SVD)
CV_SVD_SYM-对正定对称矩阵的SVD方法
函数cvSolve解决线性系统或者最小二乘法问题(后者用SVD方法可以解决):
如果使用CV_LU方法。
如果src1是非奇异的,该函数则返回1,否则返回0,在后一种情况下dst是无效的。
[编辑]
SVD
对实数浮点矩阵进行奇异值分解
voidcvSVD(CvArr*A,CvArr*W,CvArr*U=NULL,CvArr*V=NULL,intflags=0);
A
M×N的输入矩阵
W
结果奇异值矩阵(M×N或者N×N)或者向量(N×1).
U
可选的左部正交矩阵(M×MorM×N).如果CV_SVD_U_T被指定,应该交换上面所说的行与列的数目。
V
可选右部正交矩阵(N×N)
flags
操作标志;可以是0或者下面的值的组合:
CV_SVD_MODIFY_A通过操作可以修改矩阵src1。
这样处理速度会比较快。
CV_SVD_U_T意味着会返回转置矩阵U,指定这个标志将加快处理速度。
CV_SVD_V_T意味着会返回转置矩阵V,指定这个标志将加快处理速度。
函数cvSVD将矩阵A分解成一个对角线矩阵和两个正交矩阵的乘积:
这里W是一个奇异值的对角线矩阵,它可以被编码成奇异值的一维向量,U和V也是一样。
所有的奇异值都是非负的并按降序存储。
(U和V也相应的存储)。
SVD算法在数值处理上已经很稳定,它的典型应用包括:
当A是一个方阵、对称阵和正矩阵时精确的求解特征值问题,例如,当A时一个协方差矩阵时。
在这种情况下W将是一个特征值的的向量,并且U=V是矩阵的特征向量(因此,当需要计算特征向量时U和V只需要计算其中一个就可以了)。
精确的求解病态线性系统。
超定线性系统的最小二乘求解。
上一个问题和这个问题都可以用指定CV_SVD的cvSolve方法。
精确计算矩阵的不同特征,如秩(非零奇异值的数目),条件数(最大奇异值和最小奇异值的比例),行列式值(行列式的绝对值等于奇异值的乘积).上述的所有这些值都不要求计算矩阵U和V。
[编辑]
SVBkSb
奇异值回代算法(backsubstitution)
voidcvSVBkSb(constCvArr*W,constCvArr*U,constCvArr*V,
constCvArr*B,CvArr*X,intflags);
W
奇异值矩阵或者向量
U
左正交矩阵(可能是转置的)
V
右正交矩阵(可能是转置的)
B
原始矩阵A的伪逆的乘法矩阵。
这个是可选参数。
如果它被省略则假定它是一个适当大小的单位矩阵(因此x将是A的伪逆的重建).。
X
目标矩阵:
奇异值回代算法的结果
flags
操作标志,和刚刚讨论的cvSVD的标志一样。
函数cvSVBkSb为被分解的矩阵A和矩阵B计算回代逆(backsubstitution)(参见cvSVD说明):
X=V*W-1*UT*B
这里
W-1(i,i)=1/W(i,i)如果W(i,i)>epsilon?
sumiW(i,i),
否则:
0.
epsilon是一个依赖于矩阵数据类型的的很小的数。
该函数和cvSVD函数被用来执行cvInvert和cvSolve,用这些函数(svd&bksb)的原因是初级函数(low-level)函数可以避免高级函数(inv&solve)计算中内部分配的临时矩阵。
[编辑]
EigenVV
计算对称矩阵的特征值和特征向量
voidcvEigenVV(CvArr*mat,CvArr*evects,CvArr*evals,doubleeps=0);
mat
输入对称方阵。
在处理过程中将被改变。
evects
特征向量输出矩阵,连续按行存储
evals
特征值输出矩阵,按降序存储(当然特征值和特征向量的排序是同步的)。
eps
对角化的精确度(典型地,DBL_EPSILON=≈10-15就足够了)。
函数cvEigenVV计算矩阵A的特征值和特征向量:
mat*evects(i,:
)'=evals(i)*evects(i,:
)'(在MATLAB的记法)
矩阵A的数据将会被这个函数修改。
目前这个函数比函数cvSVD要慢,精确度要低,如果已知A是正定的,(例如,它是一个协方差矩阵),它通常被交给函数cvSVD来计算其特征值和特征向量,尤其是在不需要计算特征向量的情况下
[编辑]
CalcCovarMatrix
计算向量集合的协方差矩阵
voidcvCalcCovarMatrix(constCvArr**vects,intcount,CvArr*cov_mat,CvArr*avg,intflags);
vects
输入向量。
他们必须有同样的数据类型和大小。
这个向量不一定非是一维的,他们也可以是二维(例如,图像)等等。
count
输入向量的数目
cov_mat
输出协方差矩阵,它是浮点型的方阵。
avg
输入或者输出数组(依赖于标记“flags”)-输入向量的平均向量。
flags
操作标志,下面值的组合:
CV_COVAR_SCRAMBLED-输出协方差矩阵按下面计算:
scale*[vects[0]?
avg,vects[1]?
avg,...]T*[vects[0]?
avg,vects[1]?
avg,...],即协方差矩阵是count×count.这样一个不寻常的矩阵用于一组大型向量的快速PCA方法(例如,人脸识别的EigenFaces技术)。
这个混杂("scrambled")矩阵的特征值将和真正的协方差矩阵的特征值匹配,真正的特征向量可以很容易的从混杂("scrambled")协方差矩阵的特征向量中计算出来。
CV_COVAR_NORMAL-输出协方差矩阵被计算成:
scale*[vects[0]?
avg,vects[1]?
avg,...]*[vects[0]?
avg,vects[1]?
avg,...]T,也就是说,cov_mat将是一个和每一个输入向量的元素数目具有同样线性大小的通常协方差矩阵。
CV_COVAR_SCRAMBLED和CV_COVAR_NORMAL只能同时指定其中一个。
CV_COVAR_USE_AVG-如果这个标志被指定,该函数将不会从输入向量中计算avg,而是用过去的avg向量,如果avg已经以某种方式计算出来了这样做是很有用的。
或者如果协方差矩阵是部分计算出来的-倘若这样,avg不是输入向量的子集的平均值,而是整个集合的平均向量。
CV_COVAR_SCALE-如果这个标志被指定,协方差矩阵被缩放了。
thecovariationmatrixisscaled.在"normal"模式下缩放比例是1./count,在"scrambled"模式下缩放比例是每一个输入向量的元素总和的倒数。
缺省地(如果没有指定标志)协方差矩阵不被缩放(scale=1)。
函数cvCalcCovarMatrix计算输入向量的协方差矩阵和平均向量。
该函数可以被运用到主成分分析中(PCA),以及马氏距离(Mahalanobisdistance)比较向量中等等。
[编辑]
Mahalanobis
计算两个向量之间的马氏距离(Mahalanobisdistance)
doublecvMahalanobis(constCvArr*vec1,constCvArr*vec2,CvArr*mat);
vec1
第一个一维输入向量
vec2
第二个一维输入向量
mat
协方差矩阵的逆矩阵
函数cvMahalanobis计算两个向量之间的加权距离,其返回结果是:
协方差矩阵可以用函数cvCalcCovarMatrix计算出来,逆矩阵可以用函数cvInvert计算出来(CV_SVD方法是一个比较好的选择,因为矩阵可能是奇异的).
[编辑]
CalcPCA
对一个向量集做PCA变换
voidcvCalcPCA(constCvArr*data,CvArr*avg,
CvArr*eigenvalues,CvArr*eigenvectors,intflags);
data
输入数据,每个向量是单行向量(CV_PCA_DATA_AS_ROW)或者单列向量(CV_PCA_DATA_AS_COL).
avg
平均向量,在函数内部计算或者由调用者提供
eigenvalues
输出的协方差矩阵的特征值
eigenvectors
输出的协方差矩阵的特征向量(也就是主分量),每个向量一行
flags
操作标志,可以是以下几种方式的组合:
CV_PCA_DATA_AS_ROW-向量以行的方式存放(也就是说任何一个向量都是连续存放的)
CV_PCA_DATA_AS_COL-向量以列的方式存放(也就是说某一个向量成分的数值是连续存放的)
(上面两种标志是互相排斥的)
CV_PCA_USE_AVG-使用预先计算好的平均值
该函数对某个向量集做PCA变换.它首先利用cvCalcCovarMatrix计算协方差矩阵然后计算协方差矩阵的特征值与特征向量.输出的特征值/特征向量的个数小于或者等于MIN(rows(data),cols(data)).
[编辑]
ProjectPCA
把向量向某个子空间投影
voidcvProjectPCA(constCvArr*data,constCvArr*avg,
constCvArr*eigenvectors,CvArr*result)
data
输入数据,每个向量可以是单行或者单列
avg
平均向量.要么它是单行向量那么意味着输入数据以行数据的形式存放,要么就是单列向量,那么就意味着那么输入向量就是以列的方式存放.
eigenvectors
特征向量(主分量),每个向量一行.
result
输出的分解系数矩阵,矩阵的行数必须与输入向量的个数相等,矩阵的列数必须小于特征向量的行数.
该函数将输入向量向一个正交系(eigenvectors)投影.在计算点乘之前,输入向量要减去平均向量:
result(i,:
)=(data(i,:
)-avg)*eigenvectors'[编辑]
BackProjectPCA
根据投影系数重构原来的向量
voidcvBackProjectPCA(constCvArr*proj,constCvArr*avg,
constCvArr*eigenvects,CvArr*result);
proj
输入数据,与cvProjectPCA里面的格式一致
avg
平均向量.如果它是单行向量,那么意味着输出向量是以行的方式存放.否则就是单列向量,那么输出向量就是以列的方式存放.
eigenvectors
特征向量(主分量),每个向量一行.
result
输出的重构出来的矩阵
该函数根据投影系数重构原来的向量:
result(i,:
)=proj(i,:
)*eigenvectors+avg
o许多其他方法提供了更加方便的C++接口,其效率与OpenCV一样.
oOpenCV将向量作为1维矩阵处理.
o矩阵按行存储,每行有4字节的校整.
分配矩阵空间:
CvMat*cvCreateMat(introws,intcols,inttype);
?
?
type:
矩阵元素类型.格式为CV_(S|U|F)C.?
?
?
?
例如:
CV_8UC1表示8位无符号单通道矩阵,CV_32SC2表示32位有符号双通道矩阵.
?
?
例程:
?
?
CvMat*M=cvCreateMat(4,4,CV_32FC1);
释放矩阵空间:
CvMat*M=cvCreateMat(4,4,CV_32FC1);
cvReleaseMat(&M);
复制矩阵:
CvMat*M1=cvCreateMat(4,4,CV_32FC1);
CvMat*M2;
M2=cvCloneMat(M1);
初始化矩阵:
doublea[]={1,?
?
2,?
?
3,?
?
4,
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
5,?
?
6,?
?
7,?
?
8,
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
9,10,11,12};
CvMatMa=cvMat(3,4,CV_64FC1,a);
另一种方法:
CvMatMa;
cvInitMatHeader(&Ma,3,4,CV_64FC1,a);
初始化矩阵为单位阵:
CvMat*M=cvCreateMat(4,4,CV_32FC1);
cvSetIdentity(M);
间接存取矩阵元素:
cvmSet(M,i,j,;Mb?
?
->Mc
cvDiv(Ma,Mb,Mc);?
?
?
?
?
?
Mb?
?
->Mc
cvAddS(Ma,cvScalar,Mc);Vb->res
cvCrossProduct(&Va,&Vb,&Vc);?
?
?
?
单矩阵操作:
CvMat*Ma,*Mb;
cvTranspose(Ma,Mb);?
?
?
?
?
?
视频序列操作
从视频序列中抓取一帧
OpenCV支持从摄像头或视频文件(AVI)中抓取图像.
从摄像头获取初始化:
CvCapture*capture=cvCaptureFromCAM(0);在抓取动作都结束后再恢复帧图像.?
?
释放抓取源:
cvReleaseCapture(&capture);
注意由设备抓取的图像是由capture函数自动分配和释放的.不要试图自己释放它.
获取/设定帧信息
获取设备特性:
cvQueryFrame(capture);用摄像头时不对,奇怪!
!
!
.
获取帧信息:
floatposMsec?
?
?
=?
?
?
?
?
?
?
cvGetCaptureProperty(capture,CV_CAP_PROP_POS_MSEC);
intposFrames?
?
?
=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES);
floatposRatio?
?
=?
?
?
?
?
?
?
cvGetCaptureProperty(capture,CV_CAP_PROP_POS_AVI_RATIO);
获取所抓取帧在视频序列中的位置,从首帧开始按[毫秒]算.或者从首帧开始从0标号,获取所抓取帧的标号.或者取相对位置,首帧为0,末帧为1,只对视频文件有效.
设定所抓取的第一帧标号:
不过似乎也不成功!
!
!
存储视频文件
初始化视频存储器:
CvVideoWriter*writer=0;
intisColor=1;
intfps?
?
?
?
?
=25;?
?
存储视频文件:
IplImage*img=0;
intnFrames=50;
for(i=0;i?
?
cvGrabFrame(capture);?
?
?
?
?
?
?
?
?
?
释放视频存储器:
cvReleaseVideoWriter(&writer);