aihot  2017-05-12 18:32:36  OpenCV |   查看评论   

 openCV简介


这里简单的记录一些 OpenCV 这个库的使用。这是用 C/C++ 写的一个和 computer vision 相关的库,一共含有 5 个组件:
• CXCORE 是 OpenCV 里面使用的常用数据结构,以及处理这些数据结构的函数。
• CV 是常用的 computer vision 相关的函数,比如计算 histogram、目标检测、跟踪的。
• ML 是常用的 machine learning 相关的函数,如做分类的 naive Bayes、SVM 等等。
• highgui 是一些比较高层函数,主要是做用户界面。
• 另外还有一个从摄像头获取数据的 CVCAM 库,但是 1.1 里面似乎并进 highgui 了。
最新的是 1.1pre1,但是 debian 里面还是两年前的 1.0 版本的,这就需要自己编译一个了,后面有空学着 debian 的方式做个 deb 包好了。
OpenCV 的文档也算是还不错的了,除了函数的解释,部分功能还有例程、例子可以参考,这对对函数功能不是很清楚的人是非常有用的,比如我  这里不打算详细的记录 OpenCV 的每个功能,感兴趣的看文档吧。
先从 CXCORE 的基本结构讲起,OpenCV 里面提供了点 CvPoint(分 int 和 float 类型的,一般 int 的都没有后缀,float 会写 32f,double 是 64f;有 2D 和 3D 的版本),大小 CvSize、矩形 CvRect(用左下角的顶点坐标和宽、高表示)、向量 CvScalar(4 个 double 那么大)。更重要的就是存储矩阵用的 CvMat、CvMatND(多维矩阵,一般图片就是几个 channel,每个 channel 是一个 CvMat),稀疏矩阵 CvSparseMat。注意这里面有一个比较重要的成员,就是 int* refcount,这是允许多个“矩阵”(其实是 CvMatHeader 或者 CvMatNDHeader)对同一个矩阵进行引用,这时释放的时候涉及到矩阵元素的属主(ownership),只有当 refcount 为 0 的时候,释放的时候才会释放这些元素。数据的入口都是匿名 union,data 可以当作指针用。图片一般存放在一个 IplImage 结构里面,这个结构里面有很多参数决定图片数据的类型,比如是 UINT8 还是 float 等。创建这些数据最基本的函数就是 cvCreate*,这是产生一个完整的结构,并且分配数据的内存,另有一种是仅仅分配一个 header,函数就是 cvCreate*Header,之后可以用 cvSet*Data 指定数据,释放这些结构使用 cvRelease* 和 cvRelease*Header。另外可以通过 cvInit* 和 cvInit*Header 初始化这些数据结构。我们发现 OpenCV 的函数都是以 cv 开头,而结构都是 Cv 开头。另外,进行深层 copy 使用 cvClone* 函数。如果需要手工增加/减少对数据的 refcount,可以使用 cvIncRefData、cvDecRefData。OpenCV 里面的数据用 CvArr,这是一个 void 类型,因此可以自由转换成为别的类型,如果需要访问 CvArr 类型的数据,可以用 cvGetRawData,下面是一个例子:
cvGetRawData( array, (uchar**)&data, &step, &size );
step /= sizeof(data[0]);
for( y = 0; y < size.height; y++, data += step )
   for( x = 0; x < size.width; x++ )
       data[x] = (float)fabs(data[x]);这里的 data 是个 float*,因此每次递增量是 cvGetRawData 返回的 step 除以 sizeof(float)。类似的,cvGet* 命令将会返回对应的 header,如 cvGetMat、cvGetImage 等。
对于一个 CvMat,可以用 cvGetSubMat、cvGetRow(s),cvGetCol(s)、cvGetDiag 获得矩阵的部分,cvGetSize 获得矩阵的大小。遍历稀疏矩阵一般用 cvInitSparseMatIterator、cvGetNextSparseNode。另外可以用 cvGetElemType 获得元素种类,cvGetDim(s) 获得多维矩阵的大小。如果需要访问某些元素,可以用 cvPtr?D 获得指针,cvGet?D 获得元素值,另外有快速版本 cvmGet(对 2D 的矩阵)。对应有 Set 版本,用于赋值,特别的有 cvSetZero 和 cvSetIdentity 用于产生 0 矩阵和单位矩阵。另外和 matlab 类似有个 cvRange,cvReshape 改变矩阵大小,cvRepeat 和 repmat 类似,cvFlip 和 flip* 类似,cvSplit 切分矩阵,cvMerge 是逆操作。针对图片提供有 cvMixChannels。和 randperm 类似有一个 cvRandShuffle。
cvLUT 进行查表(某些图片是 indexed color),cvConvertScale 可以将不同的类型的数据(尤其是图片,有的用 float 的 0-1 表示,有的用 UINT8 表示)互相转化,它的一个特殊情况就是 cvConvertScaleAbs,cvAdd 将两个 CvArr 相加,cvAddS 加的是 scalar,cvAddWeighted 是加权和,cvSub 是相减,cvSubS 减标量,cvSubRS 是用标量减 CvArr,cvMul 是相乘,,cvDiv 是除,另外有 cvAnd(S)、cvOr(S)、cvXor(S)、cvNot、cvCmp(S);cvInRange(S) 可以检查元素是不是位于上下界中,cvMax(S)、cvMin(S) 求最大最小,cvAbsDiff(S) 求差的绝对值,cvCountNonZero 数非零元素个数,cvSum 求和,cvAvg 求平均,cvAvgSdv 计算均值和标准差,cvMinMaxLoc 返回最小最大的位置,cvNorm 计算范数(包括 、 和 )。cvReduce 将矩阵变成向量。
OpenCV 也实现了一些代数运算,比如 cvDotProduct 计算内积,cvNormalize 将向量依照某种范数归一化,cvCrossProduct 计算叉积,cvScaleAdd 将标量相加,cvGEMM 是一个广义的矩阵乘积,包括每个矩阵是不是转置,然后相乘相加(用它定义了 cvMatMulAdd 和 cvMatMul),矩阵产生的变换 cvTransform、cvPerspectiveTransform,转置相乘 cvMulTransposed,迹 cvTrace,转置 cvTranspose、行列式 cvDet,cvInvert 求逆,cvSolve 求解线性方程组,cvSVD 计算奇异值分解,cvSVBkSb 用奇异值产生原来的矩阵,求对称矩阵的特征值 cvEigenVV,cvCovarMat 计算协方差矩阵,cvMahanobis 计算马氏距离,cvCalcPCA 计算主成分分解,cvProjectPCA 进行投影,cvBackProjectPCA 重构,。
下面是 OpenCV 里面常用的数学函数,如舍入的 cvRound、cvFloor 和 cvCeil,开方系列 cvSqrt、cvInvSqrt、cvCbrt,反正切 cvFastArctan、判断 cvIsNaN、cvIsInf,坐标转换 cvCartToPolar 和 cvPolarToCart,幂函数 cvPow,指数 cvExp,对数 cvLog,求解三次方程 cvSolveCubic,一般多项式 cvSolvePoly。
另外有一些随机数相关的函数,比如 cvRNG 产生一个 random number generator,cvRandArr 产生一个随机 CvArr,cvRandInt 返回一个随机整数,cvRandReal 产生 0-1 之间的随机实数。
另外有一些和 discrete Fourier transform 相关的东西,比如 cvDFT,cvDCT 等。
OpenCV 提供了一些动态存储的数据结构,这在很多操作中非常重要,比如需要进行检测某些特征点,那么用户并不知道将会发现多少个,所以最好的方法是使用 OpenCV 的动态数据结构,不过很遗憾的是,似乎这些结构不仅不能和 STL 的容器互相转换,接口也并不统一。比较重要的类结构是 CvMemStorage,一般说来我们使用 cvCreateMemStorage 创建一个,并最后用 cvReleaseMemStorage 释放,OpenCV 里面很多函数需要 workspace 往往就是一个 CvMemStorage,如果需要自己进行更细致的操作,就需要了解一些比较基本的知识,比如它的结构是一个一个的 block 用双向链表链接(CvMemBlock 结构)而成,通过 CvMemStoragePos 记录位置,通过 cvCreateChildMemStorage 可以创建一个和 parent 相对独立的存储空间,临时存放数据非常方便。通过 cvClearMemStorage 将该结构管理的内存减到最少。CvMemStorage 提供了一个较大尺度的内存管理机制,而 CvSeq 就成为了一个容器,这个容器是一个双向链表(另有 CvSeqBlock 是个循环链表)。这个容器可以用 cvCreateSeq 创建(有一些内部支持的类型),cvSeqPush/cvSeqPop 是当作一个 stack 来进行入栈操作,类似的操作是 cvSeqPush/PopFront(队列常用操作),还可以一次插入多个 cvPush/PopMulti,插入 cvSeqInsert、删除 cvSeqRemove、删除所有元素 cvClearSeq、获得其中一个元素 cvGetSeqElem、获得一个元素的指标 cvGetElemIdx、转换成 array cvCvtSeqToArray、为 array 创建 Seq 的 header cvMakeSeqHeaderForArray,创建一个 CvSeq 的子序列 cvSlice、复制 cvCloneSeq、子序列的删除插入 cvRemove/InsertSlice、反转 cvSeqInvert、排序 cvSeqSort、搜索 cvSeqSearch。和 CvSeq 的输入输出相关的就是 CvSeqWriter 和 CvSeqReader 了,分别调用 cvStart/EndWriter/Reader 即可。
 

除特别注明外,本站所有文章均为 赢咖4注册 原创,转载请注明出处来自openCV简介

留言与评论(共有 0 条评论)
   
验证码:
[lianlun]1[/lianlun]