篇一:OpenCV矩阵运算总结
原文地址:
著作权归作者所有。 商业转载请联系作者获得授权,非商业转载请注明出处。 作者:cvvision 链接: 来源:CV视觉网 一、矩阵 Mat I,img,I1,I2,dst,A,B; double k,alpha; Scalar s; 1.加法 I=I1+I2;//等同add(I1,I2,I); add(I1,I2,dst,mask,dtype); scaleAdd(I1,scale,I2,dst);//dst=scale*I1+I2; 2.减法 absdiff(I1,I2,I);//I=|I1-I2|; A-B;A-s;s-A;-A; subtract(I1,I2,dst); 3.乘法 I=I.mul(I);//点乘,I.mul(I,3);–>I=3*I.^2 Mat C=A.mul(5/B);//==divide(A,B,C,5); A*B;矩阵相乘 I=alpha*I; Mat::cross(Mat);//三维向量(或矩阵)的叉乘,A.cross(B) double Mat::dot(Mat);//2个向量(或矩阵)的点乘的结果,A.dot(B) mul——-multiply pow(src,double p,dst);//如果p是整数dst(I)=src(I)^p;其他|src(I)|^p 4.除法 divide(I1,I2,dst,scale,int dtype=-1);//dst=saturate_cast(I1*scale/I2); A/B;alpha/A;都是点除 5.转换 I.convertTo(I1,CV_32F);//类型转换 A.t();//转置 flip(I,dst,int flipCode);//flipCode=0是上下翻转,>0时左右翻转,<0时一起来 sqrt(I,dst); cvtColor(I,dst,int code,int dstCn=0); resize:对图像进行形变 ————————————————————————– 6.其他 Scalar s=sum(I);各通道求和 norm,countNonZero,trace,determinant,repeat都是返回Mat或者Scalar countNonZero:用来统计非零的向量个数.(rows*cols个) Scalar m=mean(I);//各通道求平均 Mat RowClone=C.row(1).clone();//复制第2行 addWeight(I1,alpha,I2,beta,gamma,dst,int dtype=-1);//dst=saturate(alpha*I1+beta*I2+gamma);dtype是dst的深度 —————————————————————————- 7.运算符 log10() exp(I,dst);//dst=exp(I);计算每个数组元素的指数 log(I,dst);//如果Iij!=0;则dstij=log(|Iij|) randu(I,Scalar::all(0),Scalar::all(255)); Mat::t()转置 Mat::inv(int method=DECOMP_LU)求逆。method=DECOMP_CHOLESKY(专门用于对称,速度是LU的2倍),DECOMP_SVD//A.inv();A.inv()*B; invert(I1,dst,int method=DECOMP_LU);//用法同上 MatExpr abs(Mat)//求绝对值 A cmpop B;A compop alpha;alpha cmpop A;这里cmpop表示>,>=,==,!=,<=,<等,结果是CV_8UC1的mask的0或255 按位运算:A logicop B;A logicop s;s logicop A;~A;这里logicop代表&,|,^ bitwise_not(I,dst,mask);//inverts所有的队列 还有bitwise_and,bitwise_or,bitwise_xor, min(A,B);min(A,alpha);max(A,B);max(A,alpha);都返回MatExpr,返回的dst和A的类型一样 double determinant(Mat);//行列式 bool eigen(I1,dst,int lowindex=-1,int highindex=-1);// bool eigen(I1,dst,I,int…);//得到特征值向量dst和对应特征值的特征向量 minMaxLoc(I1,&minVal,&maxVal,Point *minLoc=0,Point* MaxLoc=0,mask); //minLoc是2D时距原点最小的点(未考证) —————————————————————————— 8.初始化 Mat I(img,Rect(10,10,100,100));//用一块地方初始化。 Mat I=img(Range:all(),Range(1,3));//所有行,1~3列 Mat I=img.clone();//完全复制 img.copyTo(I);//传递矩阵头 Mat I(2,2,CV_8UC3,Scalar(0,0,255));//I=[0,0,255,0,0,255;0,0,255,0,0,255]; Mat E=Mat::eye(4,4,CV_64F);//对角矩阵 Mat O=Mat::ones(2,2,CV_32F);//全一矩阵 Mat Z=Mat::zeros(3,3,CV_8UC1);//全零矩阵 Mat C=(Mat_<double>(2,2)<<0,-1,2,3);//如果是简单矩阵的初始化 Mat::row(i);Mat::row(j);Mat::rowRange(start,end);Mat::colRange(start,end);都只是创建个头 Mat::diag(int d);d=0是是主对角线,d=1是比主低的对角线,d=-1…. static Mat Mat::diag(const Mat& matD) Mat::setTo(Scalar &s);以s初始化矩阵 Mat::push_back(Mat);在原来的Mat的最后一行后再加几行 Mat::pop_back(size_t nelems=1);//移出最下面几行 ——————————————————————————- 9.矩阵读取和修改 (1)1个通道: for(int i=0;i<I.rows;++i) for(int j=0;j<I.cols;++j) I.at<uchar>(i,j)=k; (2)3个通道: Mat_<Vec3b> _I=I;//他没有4个通道寸,只有3个通道! for(int i=0;i<I.rows;++i) for(int j=0;j<I.cols;++j) { _I(i,j)[0]=b; _I(i,j)[1]=g; _I(i,j)[2]=r; } I=_I; ———————————————————— 或者直接用I.at<Vec3b>(i,j)[0]…. ————————————————- float *s; for(i=0;i<dealImg.rows;i++) {s=proImg.ptr<float>(i); for(j=0;j<dealImg.cols;j++) {a1=s[3*j+1]-m1; a2=s[3*j+2]-m2;}} ————————————————————————- (3)其他机制 I.rows(0).setTo(Scalar(0));//把第一行清零 saturate_cast<uchar>(…);//可以确保内容为0~255的整数 Mat::total();返回一共的元素数量 size_t Mat::elemSize();返回元素的大小:CV_16SC3–>3*sizeof(short)–>6 size_t Mat::elemSize1();返回元素一个通道的大小CV_16SC3–>sizeof(short)–>2 int Mat::type()返回他的类型CV_16SC3之类 int Mat::depth()返回深度:CV_16SC3–>CV_16S int Mat::channels()返回通道数 size_t Mat:step1()返回一个被elemSize1()除以过的step Size Mat::size()返回Size(cols,rows);如果大于2维,则返回(-1,-1),都是先宽再高的 bool Mat::empty()如果没有元素返回1,即Mat::total()==0或者Mat::data==NULL uchar *Mat::ptr(int i=0)指向第i行 Mat::at(int i)(int i,int j)(Point pt)(int i,int j,int k) RNG随机类:next,float RNG::uniform(float a,float b);.. double RNG::gaussian(double sigma); RNG::fill(I,int distType,Mat low,Mat up);//用随机数填充 randu(I,low,high); randn(I,Mat mean,Mat stddev); reduce(I,dst,int dim,int reduceOp,int dtype=-1);//可以统计每行或每列的最大、最小、平均值、和 setIdentity(dst,Scalar &value=Scalar(1));//把对角线替换为value //效果等同:Mat A=Mat::eye(4,3,CV_32F)*5; ————————————————————– 10.较复杂运算 gemm(I1,I2,alpha,I3,beta,dst,int flags=0);//I1至少是浮点型,I2同I1,flags用来转置 //gemm(I1,I2,alpha,I3,beta,dst,GEMM_1_T,GEMM_3_T);–>dst=alpha*I1.t()*I2+beta*I3.t();可用此完全代替此函数 mulTransposed(I,dst,bool aTa,Mat delta=noArray(),double scale=1,int rtype=-1); //I是1通道的,和gemm不同,他可用于任何类型。 //如果aTa=flase时,dst=scale*(I-delta).t()*(I-delta); //如果是true,dst=scale*(I-delta)(I-delta).t(); calcCovarMatrix(Mat,int,Mat,Mat,int,int=);calcCovarMatrix(Mat I,Mat covar,Mat mean,int flags,int=); cartToPolar//转到极坐标 compare(I1,I2,dst,cmpop);cmpop=CMP_EQ,CMP_GT,CMP_GE,CMP_LT,CMP_LE,COM_NE completeSymm(M,bool lowerToUpper=false);当lowerToUpper=true时Mij=Mji(i<j);当为flase时,Mij=Mji(i>j) 变成可显示图像:convertScaleAbs(I,dst,alpha,beta);dst=saturate_cast<uchar>(|alpha*I+beta|); dct(I,dst,int flags=0);//DCT变换,1维、2维的矩阵;flags=DCT_INVERSE,DCT_ROWS idct,dft,idft inRange(I1,I_low,I_up,dst);//dst是CV_8UC1,在2者之间就是255 Mahalanobis(vec1,vec2,covar); merge(vector<Mat>,Mat);//把多个Mat组合成一个和split相反 double norm(…):当src2木有时,norm可以计算出最长向量、向量距离和、向量距离和的算术平方根 solveCubic解3次方程,solvePoly解n次方程 排列:sort,sortIdx mixChannels();对某个通道进行各种传递 —————————————————————– 11.未懂的函数 getConvertElem,extractImageCOI,LUT magnitude(x,y,dst);//I1,I2都是1维向量,dst=sqrt(x(I)^2+y(I)^2); meanStdDev, MulSpectrums(I1,I2,dst,flags);傅里叶 normalize(I,dst,alpha,beta,int normType=NORM_L2,int rtype=-1,mask);//归一化 PCA,SVD,solve,transform,transpose 二、其他数据结构 Point2f P(5,1); Point3f P3f(2,6,7); vector<float> v;v.push_back((float)CV_PI);v.push_back(2);v.push_back(3.01f);//不断入 vector<Point2f> vPoints(20);//一次定义20个 三、常用方法 Mat mask=src<0;这样很快建立一个mask了 四、以后可能用到的函数 randShuffle,repeat 五、矩阵处理 1、矩阵的内存分配与释放 (1) 总体上: Opencv 使用C语言来进行矩阵操作。不过实际上有很多C++语言的替代方案可以更高效地完成。 在OpenCV中向量被当做是有一个维数为1的N维矩阵. 矩阵按行-行方式存储,每行以4字节(32位)对齐. (2) 为新矩阵分配内存: CvMat* cvCreateMat(int rows, int cols, int type); type: 矩阵元素类型. 按CV_<bit_depth>(S|U|F)C<number_of_channels> 方式指定. 例如: CV_8UC1 、CV_32SC2. 示例: CvMat* M = cvCreateMat(4,4,CV_32FC1); (3) 释放矩阵内存: CvMat* M = cvCreateMat(4,4,CV_32FC1); cvReleaseMat(&M); (4) 复制矩阵: CvMat* M1 = cvCreateMat(4,4,CV_32FC1); CvMat* M2; M2=cvCloneMat(M1); (5) 初始化矩阵: 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); (6) 初始化矩阵为单位矩阵: CvMat* M = cvCreateMat(4,4,CV_32FC1); cvSetIdentity(M); // does not seem to be working properl 2、访问矩阵元素 (1) 假设需要访问一个2D浮点型矩阵的第(i, j)个单元. (2) 间接访问: cvmSet(M,i,j,2.0); // Set M(i,j) t = cvmGet(M,i,j); // Get M(i,j) (3) 直接访问(假设矩阵数据按4字节行对齐): CvMat* M = cvCreateMat(4,4,CV_32FC1); int n = M->cols; float *data = M->data.fl; data[i*n+j] = 3.0; (4) 直接访问(当数据的行对齐可能存在间隙时 possible alignment gaps): CvMat* M = cvCreateMat(4,4,CV_32FC1); int step = M->step/sizeof(float); float *data = M->data.fl; (data+i*step)[j] = 3.0; (5) 对于初始化后的矩阵进行直接访问: double a[16]; CvMat Ma = cvMat(3, 4, CV_64FC1, a); a[i*4+j] = 2.0; // Ma(i,j)=2.0; 3、矩阵/向量运算 (1) 矩阵之间的运算: 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 (2) 矩阵之间的元素级运算: 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 (3) 向量乘积: 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 注意在进行叉乘运算时,Va, Vb, Vc 必须是仅有3个元素的向量. (4) 单一矩阵的运算: CvMat *Ma, *Mb; cvTranspose(Ma, Mb); // 转置:transpose(Ma) -> Mb (注意转置阵不能返回给Ma本身) CvScalar t = cvTrace(Ma); // 迹:trace(Ma) -> t.val[0] double d = cvDet(Ma); // 行列式:det(Ma) -> d cvInvert(Ma, Mb); // 逆矩阵:inv(Ma) -> Mb (5) 非齐次线性方程求解: 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 (6) 特征值与特征向量 (矩阵为方阵): 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 = 对应的特征向量 (行向量) (7) 奇异值分解(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按转置形式返回 (若不转置可能运算出错). 篇二:OpenCV的基本矩阵操作与示例