【矩阵处理】
1. 内存的分配与释放
因为OpenCV使用C语言来进行矩阵操作,但是用C++的替代方案可以更加高效地完成操作。
在OpenCV中向量被当做是有一个维数为1的N维矩阵。
矩阵按照行—行方式存储,每行4byte(32bit)对齐。
2. 为新的矩阵分配内存
CvMat *cvCreateMat(int rows, int cols , int type);
其中 Type是矩阵元素的类型:
CV(S|U|F)C方式指定
Eg: 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);
7. 访问矩阵元素
假设我们现在需要访问一个2D浮点型矩阵的第(i,j)个单元
1. 间接访问
cvmSet(M,I,j,2.0); //设置M的(I,j)位置的值为2.0
t=cvmGet(M,I,j)
2. 直接访问(假设矩阵按照4字节对齐)
CvMat *M=cvCreateMat(4,4,CV_32FC1);
Int n =M->cols;
Float *data= M->data.f1;
Data[i*n+j]=3.0;
3. 直接访问(当数据的对齐可能存在间隙的时候)
CvMat *M=cvCreateMat(4,4,CV_32FC1);
Int step=M->Setp/sizeof(float);
Float *data=M->data.f1;
(data+i*step)[j]=3.0;
4. 对于初始化后的矩阵进行直接访问
double a[16];
CvMat Ma=cvMat(3,4,CV_64FC1,a);
a[i*4+j]=2.0
【基本运算】
1. 矩阵之间的运算
CvMat *Ma,*Mb,*Mc;
cvAdd(Ma,Mb,Mc);
cvSub(Ma,Mb,Mc);
cvMatMul(Ma,Mb,Mc);
2. 矩阵之间的元素级运算
CvMat *Ma,*Mb,*Mc;
cvMul(Ma,Mb, Mc);
cvDiv(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);//向量点乘
cvCrossProduct(&Va,&Vb,&vc);//向量叉乘
4. 单一矩阵的运算
CvMat * Ma,* Mb;
cvTranspos(Ma,Mb);//转置 transpose(Ma)->Mb(转置不能返回给Ma本身
CvScalar t=cvTrace(Ma);
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 *I=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=UDV^T
标志位使得矩阵U或者V按照转置的形式返回(若不转置可能运算出错)
【OpenCV视频处理】
1. 从视频流中捕捉一帧画面
(1) OpenCV支持从摄像头或者视频文件(AVI格式)中捕捉帧画面;
(2) 初始化一个摄像头捕捉器:
CvCapture *capture=cvCaptureFromCAM(0);
(3) 初始化一个视频文件捕捉器:
CvCapture *capture=cvCaptureFromAVI(“infile.avi”);
(4) 捕捉一帧画面:
IplImage *img=0;
If(!cvGrabFrame(capture)){ 捕捉一帧
Printf(“could not grav a frame\n\7”);
Exit(0);
}
Img=cvRetrieveFrame(capture); //检索捕捉到的这一帧给图像img
若要从多个摄像头中同步捕捉画面,则必须先从每个摄像头中抓取一帧,紧接着要将被捕捉的帧画面恢复到一个IplImage *型图像中。(这个过程可以使用cvQueryFrame()函数一步完成;
(5) 释放视频流捕捉器:
cvReleaseCapture(&capture);
2. 获取/设置视频流信息
(1) 获取视频流设备信息:
CvQueryFrame(capture);//在读取视频流信息之前,要先执行此操作
int frameH=(int)cvGetXaptureProperty(capture,CV_CAP_PROP_FRAME_HEIGHT);
int frameW=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_WIDTH);
int fps=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FPS);
int numFrames=(int)cvGetCaptureProperty(capture,CV_CAP_PROP_FRAME_COUNT);
fps仅仅对于视频文件有效,但是不太准确
(2) 获取帧图信息:
float posMsec=cvGetCaptureProperty(capture,CV_CAP_PROP_POS_MSEC):
int posFrames=(int) cvGetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES):
float posRatio=cvGetCaptureProperty(capture,CV_CAP_PROP_POS_AVI_RATIO);
(3) 设置从视频文件抓取第一帧画面的位置:
CvSetCaptureProperty(capture,CV_CAP_PROP_POS_AVI_RATIO,(double)0.9);
3. 保存视频文件
(1) 初始化视频编写器:
CvVideoWriter *writer=0;
int isColor=1;
int fps=25;
int frameW =640;
int frameH=480;
write=cvCreateVideoWriter(“out.avi”,CV_FOURCC(‘P’,’I’,’M’,’1’),
fps,cvSize(frameW,frameH),isColor)
其他的编码器代号包括:
其它的编码器代号包括: CV_FOURCC('P','I','M','1') = MPEG-1 codec CV_FOURCC('M','J','P','G') = motion-jpeg codec (does not work well) CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec CV_FOURCC('U', '2', '6', '3') = H263 codec CV_FOURCC('I', '2', '6', '3') = H263I codec CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec 若编码器代号为 -1,则运行时会弹出一个编码器选择框.
(2) 保持视频文件
IplImage *img=0;
Int nFrames=50;
for(i=0;i
{
cvGrabFrame(capture); //捕捉一帧
img=cvRetrieveFrame(capture);//重新保存这帧图像在img中
//img=cvQueryFrame(capture);
cvWriteFrame(write,img);
}
要查看所抓取到的帧画面,在循环中加入下列语句即可:
cvShowImage(“mainWin”,img);
key=cvWaitKey(20);
注意显示的时候cvWaitkey不能小于20ms,否则画面的显示可能出错。
(3) 释放视频编写器
cvReleaseVideoWriter(&writer);