opencv总结Mat,IplImage操作

转载

  • 综述:

    • 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。

//////////////////////////////////////////////////////////////////////////////////////////////////

     自己遇到的问题:

    1,首先是初始化的问题,opencv提供了初始化Mat和初始化MatHead两种方法,文档中介绍都不分配内存存储数据,但实际上cvCreateMat这个函数是分配空间的,类推IplImage也是这样。不初始化会在运行时报错。

    2,为了调用SVD函数,我要用到很多Mat类型的数据,而且要从IplImage转化为Mat,这里可以选择两个函数,一个是cvGetImage,一个是cvConvert。cvGetImage会将输入数据的文件头一并复制,不符合我的要求,我的输入是IPL_DEPTH_8U ,要转化的矩阵是CV_32FC1,第二个函数不会复制文件头。另外要注意,Mat类型中的type包含很多信息,不光有矩阵的数据类型,不要尝试在矩阵复制后,更改type达到上面的目的。更改type会导致release不成功。

    3,opencv不支持不同大小的矩阵相加,我又初始化一个载体大小的图像,将水印的奇异值矩阵复制过去,这是我程序为数不多的几次自己编写的程序块,注意更改单个矩阵值的函数是cvmSet和cvmGet。不要自己找啊。

    4,cvCreateMat函数并不会对数据进行初始化,最好继续用cvSet对数据进行初始化。

你可能感兴趣的:(opencv学习笔记)