数组就是一维矩阵,很多操作是相同的,这里放到一起。重点是列出和Mat有关的操作。
OpenCV有很多函数有mask,代表掩码,如果某位mask是0,那么对应的src的那一位就不计算,mask要和矩阵/ROI/的大小相等。大多数函数支持ROI,如果图像ROI被设置,那么只处理ROI部分。少部分函数支持COI,如果COI设置,只处理感兴趣的通道。
如果C++版本和C版本的函数名只差一个cv,则只列C++版本的。否则都列出来。
1. Mat类内部方法
设为A,B为Mat类型,s是Scalar类型,a是一个实数。下面列出关于Mat的常用运算:
- 矩阵加减: A+B,A-B,A+s,A-s,s+A,s-A,-A.
- 矩阵乘以实数: A*a,a*A
- 逐元素乘除: A.mul(B),A/B,a/A
- 矩阵乘法: A*BmaxVal; Point minPos,m
- 矩阵倒置: A.t()
- 矩阵的逆: A.inv()
- 矩阵比较: A comp B,A comp a,a comp A。这里comp包括 >, >=,==,!=,<=,<。得出的结果是一个单通道8位的矩阵,元素的值为255或0。
- 矩阵位操作: A logic B, A logic s,s logic A。这里logic包括:&,|,^
- 向量的差乘和内积: A.cross(B),A.dot(B);
这里需要注意,为防止溢出,矩阵乘法的矩阵元素类型至少是float,即CV_32F以上。OpenCV除了提供上述提到的直接调用Mat成员函数(如求逆,倒置)的以及使用Mat重载操作符(如加减乘除)的方法外,还提供了外部函数实现这些功能。
2. 矩阵的代数运算
矩阵的加减乘除
矩阵与矩阵
void add(InputArray src1, InputArray src2,OutputArray dst, InputArraymask=noArray(), int dtype=-1)`
void subtract(InputArray src1, InputArraysrc2, OutputArray dst,InputArray mask=noArray(), int dtype=-1)
void multiply(InputArray src1, InputArraysrc2, OutputArray dst, doublescale=1, int dtype=-1 )
void divide(InputArray src1, InputArraysrc2, OutputArray dst, doublescale=1, int dtype=-1)
void cvAdd(const CvArr*src1,constCvArr*src2,CvArr* dst,const CvArr* mask =NULL);
void cvSub(const CvArr* src1, constCvArr*src2, CvArr* dst, constCvArr* mask=NULL);
void cvMul(const CvArr* src1,constCvArr*src2,CvArr* dst,doublescale=1);
void cvDiv(const CvArr* src1,constCvArr*src2, CvArr* dst, doublescale=1);
矩阵与数
void cvAddS(const CvArr*src,CvScalarvalue,CvArr*dst,const CvArr*mask = NULL);
void cvSubS(const CvArr* src,CvScalarvalue, CvArr* dst, constCvArr* mask=NULL);
void cvSubRS(const CvArr* src,CvScalarvalue, CvArr* dst, constCvArr* mask=NULL);
高级混合运算
void addWeighted(InputArray src1,doublealpha, InputArray src2, double beta, double gamma, OutputArray dst, intdtype=-1);
带权值加法,dst= alpha* src1 + beta *src2 + gamma
void gemm(InputArray src1, InputArraysrc2,double alpha, InputArray src3, double gamma, OutputArray dst, int flags=0);
矩阵的广义乘法。其中, * src1,src2的type必须是CV_32FC1, CV_64FC1, CV_32FC2, or CV_64FC2 * flag是控制矩阵转置的: *GEMM_1_T转置 src1. * GEMM_2_T 转置 src2. * GEMM_3_T 转置 src3.
void scaleAdd(InputArray src1, doublescale,InputArray src2, OutputArray dst)
//dst = scale*src1 + src2
矩阵的绝对值
MatExpr abs(const Mat& m)
void absdiff(InputArray src1, InputArraysrc2, OutputArray dst)
void absdiff(InputArray src1, InputArraysrc2, OutputArray dst)两矩阵相减取绝对值
void cvAbsDiffS(const CvArr* src, CvArr*dst,CvScalarvalue);//矩阵减去一个数取绝对值
矩阵的比较
void cvCmp(constCvArr* src1, constCvArr* src2, CvArr* dst, int cmp_op);
void compare(InputArray src1, InputArraysrc2, OutputArray dst, int cmpop)
mpop是标志位,指定比较符号:
CMP_EQ src1等于src2.
CMP_GT src1大于src2.
CMP_GE src1大于等于src2.
CMP_LT src1小于src2.
CMP_LE src1小于等于src2.
CMP_NE src1不等于src2.
如果两个矩阵的对应元素比较结果为true,则dst中相应的元素设置为255。
void cvCmpS(constCvArr* src, double value, CvArr* dst, intcmp_op);//矩阵和一个数字比较运算
矩阵的逻辑运算
void bitwise_and(InputArray src1,InputArray src2, OutputArray dst, InputArray mask=noArray())
void bitwise_not(InputArray src,OutputArray dst, InputArray mask=noArray())
void bitwise_or(InputArray src1, InputArraysrc2, OutputArray dst, InputArray mask=noArray())
void bitwise_xor(InputArray src1,InputArray src2, OutputArray dst, InputArray mask=noArray())
void cvAnd(const CvArr* src1,const CvArr*src2, CvArr* dst, const CvArr* mask=NULL);
void cvOr(const CvArr* src1, const CvArr*src2, CvArr* dst, constCvArr* mask=NULL);
void cvNot(const CvArr* src,CvArr* dst);//矩阵取反
void cvXor(const CvArr* src1, const CvArr*src2, CvArr* dst, constCvArr* mask=NULL);
void cvAndS(const CvArr* src, CvScalar value,CvArr* dst, constCvArr* mask=NULL);
void cvOrS(const CvArr* src, CvScalarvalue, CvArr* dst, constCvArr* mask=NULL);
void cvXorS(const CvArr* src, CvScalarvalue, CvArr* dst, constCvArr* mask=NULL);
矩阵的对数、幂、指数
逐元素求解矩阵的对数:
void log(InputArray src, OutputArray dst)
逐元素计算矩阵的以e为底的指数:
void exp(InputArray src, OutputArray dst)
逐元素计算矩阵的幂
void pow(InputArray src, double power,OutputArray dst)
矩阵的范数
矩阵的范数运算提供了多种范数的运算方法,下面是函数声明:
double norm(InputArray src1, intnormType=NORM_L2, InputArray mask=noArray())
double norm(InputArray src1, InputArraysrc2, int normType=NORM_L2, InputArray mask=noArray() )
其中,第二种调用是,求的src1和src2的差值的范数,各个参数意义如下:
src1, src2:输入矩阵
normType:范数的类型,主要有NORM_INF,NORM_L1,NORM_L2
此外,OpenCV还提供了把归一化范数的计算,即把计算的值归一化到某个范围内:
void normalize(InputArray src, OutputArraydst, double alpha=1, double beta=0, int norm_type=NORM_L2, int dtype=-1,InputArray mask=noArray() )
其中,alpha是范围的下限,beta是范围上限
矩阵的转置和逆
double invert(InputArray src, OutputArraydst, int flags=DECOMP_LU)
void transpose(InputArray src, OutputArraydst)
void mulTransposed(InputArray src,OutputArray dst, bool aTa, InputArray delta=noArray(), double scale=1, intdtype=-1 )
dst=scale(src−delat)∗(src−delta)T if aTa = true
dst=scale(src−delat)T∗(src−delta) if aTa =false
向量的内积、外积
内积和外积是针对向量的。
内积,也叫叉积、向量积。a×b = |a||b|sin<a,b>
外积,也叫点积、数量积。a·b = a1b1+a2b2+…+anbn
void cvCrossProduct(const CvArr* src1,constCvArr* src2,CvArr*dst);//计算两个3D向量内积
double cvDotProduct(const CvArr* src1,const CvArr*src2);//两个向量外积
矩阵的卷积
和内积外积不同,卷积是针对矩阵的。对于图像,做卷积就是进行滤波。说到滤波,OpenCV有很多方法,这里只给出一个方法。
void filter2D(InputArray src, OutputArraydst, int ddepth, InputArray kernel, Point anchor=Point(-1,-1), double delta=0,int borderType=BORDER_DEFAULT )
//对图像进行线性滤波
矩阵的迹
矩阵的迹就是矩阵对角线元素的和
Scalar trace(InputArray mtx)
矩阵对应行列式值
double determinant(InputArray mtx)
直接返回行列式的值。输入矩阵的类型必须是CV_32F或CV_64F的方阵
double cvDet(const CvArr*mat);
矩阵的特征值和特征向量
bool eigen(InputArray src, OutputArrayeigenvalues, int lowindex=-1, int highindex=-1)
bool eigen(InputArray src, OutputArrayeigenvalues, OutputArray eigenvectors, int lowindex=-1, int highindex=-1)
输入矩阵的类型必须是CV_32F或CV_64F的方阵, eigenvalues存储计算的特征值,eigenvectors存储计算的特征向量,lowindex和highindex输出最小最大特征值对于的索引,但是目前该功能不能用。
矩阵的最小二乘
bool solve(InputArray src1, InputArraysrc2, OutputArray dst, int flags=DECOMP_LU)
该函数解决了一个线性系统或最小二乘问题
矩阵的奇异值分解
C++中SVD是一个类,详细用法去搜
void cvSVD(CvArr*A, CvArr* W, CvArr* U=NULL, CvArr* V=NULL, intflags=0);
void cvSVBkSb(const CvArr* W, const CvArr* U,const CvArr* V, constCvArr* B, CvArr* X, int flags);
3. 矩阵的统计运算
矩阵的元素和
Scalar sum(InputArray src)
其中,多通道是单独计算各个通道内的元素和。
矩阵非零元素个数
int countNonZero(InputArray src)
函数返回矩阵的非零元素的个数。
矩阵的均值和方差
元素的均值和方差的函数如下:
Scalar mean(InputArray src, InputArray mask=noArray()) //只计算均值
void meanStdDev(InputArray src, OutputArraymean, OutputArray stddev, InputArray mask=noArray())
这里计算的方差其实就是归一化的协方差矩阵的对角线的和。
CvScalarcvAvg(const CvArr* arr,constCvArr* mask =NULL);// 计算mask非零位置的所有元素的平均值,如果是图片,则单独计算每个通道上的平均值
协方差矩阵
协方差矩阵表示的是高维度随机变量中各个元素之间的协方差。计算协方差矩阵的函数为:
void calcCovarMatrix(const Mat* samples,int nsamples, Mat& covar, Mat& mean, int flags, int ctype=CV_64F)
void calcCovarMatrix(InputArray samples, OutputArraycovar, OutputArray mean, int flags, int ctype=CV_64F)
其中第一种调用其实是直接调用的第二个调用方式。对于第一种调用,samples是输入的随机向量指针,nsamples是个数。对于第二种调用,sample是以矩阵的形式存储随机向量,通过flag的值指定是列向量还是行向量。。
马氏距离
马氏距离是计算数据的协方差距离,是一种有效的计算两组数据相似性的度量。和欧氏距离不同,马氏距离考虑各种特性之间的联系。调用函数如下:
double Mahalanobis(InputArray v1,InputArray v2, InputArray icovar)
矩阵的最大最小值
计算元素的最大最小值,OpenCV针对不同的情况,提供了较多的函数,
最大值
MatExpr max(const Mat& a, constMat& b)
MatExpr max(const Mat& a, double s)
MatExpr max(double s, const Mat& a)
void max(InputArray src1, InputArray src2,OutputArray dst)
void max(const Mat& src1, constMat& src2, Mat& dst)
void max(const Mat& src1, double src2,Mat& dst)
最小值:
MatExpr min(const Mat& a, constMat& b)
MatExpr min(const Mat& a, double s)
MatExpr min(double s, const Mat& a)
void min(InputArray src1, InputArray src2,OutputArray dst)
void min(const Mat& src1, constMat& src2, Mat& dst)
void min(const Mat& src1, double src2,Mat& dst)
还有能给出最大最小值的函数如下:
void minMaxIdx(InputArray src, double*minVal, double* maxVal, int* minIdx=0, int* maxIdx=0, InputArraymask=noArray())
void minMaxLoc(InputArray src, double*minVal, double* maxVal=0, Point* minLoc=0, Point* maxLoc=0, InputArraymask=noArray())
这两个函数调用很类似,主要不同在于最大最小值的位置的输出不同。minMaxIdx()的最大最小值位置坐标顺序地存储在maxIdx和minIdx数组中,而minMaxLoc()则直接存储在Point中,注意minMaxIdx()存储是按照维数排列的,即行、列。而minMaxLoc()存储的Point是按照坐标x,y存储的,即列、行。
检查矩阵元素的范围
bool checkRange(InputArray a, boolquiet=true, Point* pos=0, double minVal=-DBL_MAX, double maxVal=DBL_MAX )
检查矩阵a中的元素有没有超过[minVal,maxVal]这个范围,pos记录元素位置,标志位quiet决定是否抛出异常还是仅仅返回bool值false。
void cvInRange(const CvArr*src,const CvArr*lower,const CvArr* upper,CvArr* dst);
void cvInRangeS(const CvArr* src,CvScalarlower,CvScalarupper,CvArr* dst);//判断原数组中的每个数大小是否落在对应的lower、upper数组位置数值的中间
4. 矩阵的各种变换
颜色空间转换
void cvtColor(InputArray src, OutputArraydst, int code, int dstCn=0 )
格式转换
Mat转CV_8U
void cvConvertScale(const CvArr* src,CvArr* dst, double scale=1, double shift=0)
除了前面Mat详解中介绍的Mat::convertTo()可实现类型的转换外,OpenCV还提供了如下函数,实现一个组合功能即:缩放,求绝对值,转换类型到8-bit
void convertScaleAbs(InputArray src,OutputArray dst, double alpha=1, double beta=0)
其实现的结果是
dst(I)=saturatecast<uchar>(|src(I)∗alpha+beta|)
dst(I)=saturatecast<uchar>(|src(I)∗alpha+beta|)
Ipllmage、CvMat和Mat的转换
除了前面Mat详解中介绍的直接转换方式外,OpenCV还提供了如下函数进行转换:
Mat cvarrToMat(const CvArr* arr, boolcopyData=false, bool allowND=true, int coiMode=0 )
其中,
CvArr——是CvMat,IplImage,CvMatND类型的数组
copyData——决定是否拷贝数据,如果为true,则拷贝到新的结构体中,否则仅创建一个头,指向原数据。
allowND——决定是否支持多维数组,如果为true,则把多维数组转换到一个二维数组中,如果不能转换,则返回错误。
coiMode——这个标识符是为IplImage的指定通道设置的,类似ROI的COI(Channelof Interest)。如果coiMode=0,且IPlImage的COI是设置的,则返回错误;如果coiMode=1,则不返回错误,而是直接返回整个原始图像的头,需要自己通过函数extractImageCOI()单独提取相应的通道。
通道的改变
通道的合成与分解
把多通道的矩阵分拆到多个矩阵的函数
void split(const Mat& src, Mat*mvbegin)
把多个矩阵合并到一个多通道矩阵
void merge(const Mat* mv, size_t count,OutputArray dst)
还有一个更通用的函数,可以把多个矩阵的相关通道分拆或合并到其他矩阵中
void mixChannels(const Mat* src, size_tnsrcs, Mat* dst, size_t ndsts, const int* fromTo, size_t npairs)
void mixChannels(constvector<Mat>& src, vector<Mat>& dst, const int* fromTo,size_t npairs)
通道的提取与嵌入
针对OpenCV的老的数据结构CvMat和IplImage,OpenCV还提供了另外两个函数实现相关操作:
void extractImageCOI(const CvArr* arr,OutputArray coiimg, int coi=-1 )
void insertImageCOI(InputArray coiimg,CvArr* arr, int coi=-1 )
其中,extractImageCOI()是实现提取arr中的某一通道,到coiimg中去;coiimg必须为单通道。insertImageCOI是把单通道的coiimg嵌入到arr中去;如果coi>=0,则提取对应coi通道的矩阵,否则,提取IplImage标记的COI通道
旋转
void flip(InputArray src, OutputArray dst,int flipCode)
图像绕x、y轴旋转。
查表替换矩阵元素
OpenCV提供了一个查表替换矩阵中元素的操作,函数声明如下:
void LUT(InputArray src, InputArray lut,OutputArray dst, int interpolation=0 )
src是一个8位的矩阵,lut是一个256的查询表,依照lut中对每个值的映射,替换相应的元素值,存储到dst中去。其实现的操作如下:
dst(I)=lut(src(I)+d)
dst(I)=lut(src(I)+d)
d={0,128,如果src.depth()=CV_8U;如果src.depth()=CV_8S;
d={0,如果src.depth()=CV_8U;128,如果src.depth()=CV_8S;
对角拷贝
OpenCV还提供了一种对角拷贝的操作,即把右上角的元素拷贝到左下角,或者相反,中间对角线元素不变。函数如下:
void completeSymm(InputOutputArray mtx,bool lowerToUpper=false)
其中lowerToUpper设置为true的时候,左下角拷贝到右上角,反之,右上角拷贝到左下角。
柱坐标转极坐标
两个矩阵对应元素组成的一系列二维坐标的的极角和极径的计算可以使用如下函数:
void cartToPolar(InputArray x, InputArrayy, OutputArray magnitude, OutputArray angle, bool angleInDegrees=false)
反过来,可以通过极坐标下的极角和极径,计算出对于的二维向量坐标:
void polarToCart(InputArray magnitude,InputArray angle, OutputArray x, OutputArray y, bool angleInDegrees=false)
除此之外,还可以单独计算二维坐标的极角和极径,函数调用为:
void magnitude(InputArray x, InputArray y,OutputArray magnitude)
void phase(InputArray x, InputArray y,OutputArray angle, bool angleInDegrees=false)