/* *CvMat矩陣頭 */ typedef struct CvMat { int type; //數據類型,比如CV_32FC1含義是32位浮點型單通道,再比如CV_8UC3含義是8位無符號整型三通道 int step; //每行數據的字節數:元素個數*元素類型的字節長度 int* refcount;/* for internal use only */ int hdr_refcount; union { uchar* ptr; //指向data數據的第一個元素 short* s; int* i; float* fl; double* db; } data; //共同體data,里面成員公用一個空間,也就是說數據類型可以有這五種。 union { int rows; //像素的行數 int height; //圖片的高度 }; union { int cols; //像素的列數 int width; //圖片的寬度 }; } CvMat;
矩陣基本操作:
// vv.cpp : 定義控制台應用程序的入口點。 #include <stdio.h> #include <cv.h> #include <highgui.h> #include "cvaux.h" //必須引此頭文件 #include "cxcore.h" using namespace std; int main( int argc, char** argv ) { int i = 0; float b[6] = {0,}; float a[36] = {0,}; /******************矩陣的創建與克隆*********************/ for( i = 0; i < 6; i++) b[i] = i + 1; //b[i]存放那六個系數 CvMat *Mb = cvCreateMat(6, 1, CV_32FC1); //矩陣的創建 //創建 6行1列 矩陣Mb cvSetData(Mb,b,CV_AUTOSTEP); //矩陣賦值 printf("type:%d step:%d",Mb->type, Mb->step); CvMat *MbClone=cvCloneMat(Mb); //矩陣克隆 for( i=0;i<6;i++) //打印輸出該矩陣 { if(i % 3 == 0) printf("\n"); printf("%f\t",Mb->data.fl[i]); } printf("\n"); for( i=0;i<6;i++) //打印輸出該矩陣 { if(i % 3 == 0) printf("\n"); printf("%f\t",MbClone->data.fl[i]); } printf("\n"); for( i = 0; i < 36; i++) a[i] = i + 1; CvMat *Ma = cvCreateMat(6, 6, CV_32FC1); //左邊的坐標矩陣 cvSetData(Ma,a,CV_AUTOSTEP); printf("type:%d step:%d",Ma->type, Ma->step); for( i=0;i<36;i++) { if(i%5==0) printf("\n"); printf("%f\t",Ma->data.fl[i]); } printf("\n"); /******************矩陣創建分解實現 *****************/ //cvCreatMatHeader //cvCreatMatData //cvInitMatHeader float vals[]={0.862633, -0.523233, 0.500000, 0.866623}; CvMat rotmat; cvInitMatHeader(&rotmat, 2, 2, CV_32FC1, vals); //依據存在的矩陣初始化矩陣頭 CvMat *rotmatpro = cvCreateMatHeader(2,2,CV_32FC1); //創建矩陣頭,不分配數據空間 CvMat MatCreat=cvMat(2,2,CV_32FC1, vals); printf("type:%d step:%d", rotmatpro->type, rotmatpro->step); printf("\n"); for( i=0;i<4;i++) //打印輸出該矩陣 { printf("%f\t",rotmat.data.fl[i]); } printf("\n"); for( i=0;i<4;i++) //打印輸出該矩陣 { printf("%f\t",MatCreat.data.fl[i]); } printf("\n"); /*******************矩陣的求解***********************/ CvMat* Mx = cvCreateMat(6, 1,CV_32FC1); //要求解的矩陣 cvSolve(Ma, Mb, Mx, CV_LU ); //矩陣的求解 solve (Ax=b) for x for( i=0;i<6;i++) { if(i%3==0) printf("\n"); printf("%f\t",Mx->data.fl[i]); } cvReleaseMat(&Ma); //矩陣的釋放 cvReleaseMat(&Mb); cvReleaseMat(&Mx); getchar(); return 0; }
注意:OpenCV中矩陣的行和列是從序號0開始的。且下面的5,1 按平時的習慣指的是第6行,第2列。
矩陣數據的存取很少用到,不再多說了。
/*****************矩陣數據的存取*********************/ //宏,下面僅用於一二維數組的數據存取 float MaElem5_1=CV_MAT_ELEM(*Ma, float, 5, 1); float MaElem5_1Int=CV_MAT_ELEM(*Ma, int, 5, 1); float newValue=7.7; *((float*)CV_MAT_ELEM_PTR(*Ma, 5, 1))=newValue; //cvPtr*D 處理多維矩陣 //cvGetRealND 讀取多維矩陣數據 //cvGetND
//cvmGet
//cvmSet
/****************************************************/
下面參考http://blog.csdn.net/augusdi/article/details/8864950
初始化矩陣為單位陣:
- CvMat* M = cvCreateMat(4,4,CV_32FC1);
- cvSetIdentity(M); // 這里似乎有問題,不成功
存取矩陣元素
假設需要存取一個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;
- (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
按元素的矩陣操作:
- 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 -> Vcend{verbatim}
注意 Va, Vb, Vc 在向量積中向量元素個數須相同.
單矩陣操作:
- CvMat *Ma, *Mb;
- cvTranspose(Ma, Mb); // transpose(Ma) -> Mb (不能對自身進行轉置)CvScalar
- double d = cvDet(Ma); // det(Ma) -> dcvInvert(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 返回時被轉置(若沒有轉置標號,則有問題不成功!!!).
視頻序列操作
從視頻序列中抓取一幀
OpenCV支持從攝像頭或視頻文件(AVI)中抓取圖像.
從攝像頭獲取初始化:
- CvCapture* capture = cvCaptureFromCAM(0); // capture from video device #0
從視頻文件獲取初始化:
- CvCapture* capture = cvCaptureFromAVI("infile.avi");
抓取幀:
- IplImage* img = 0; if(!cvGrabFrame(capture))
- {
- // 抓取一幀
- printf("Could not grab a frame\n\7");
- exit(0);
- }
- img=cvRetrieveFrame(capture); // 恢復獲取的幀圖像
要從多個攝像頭同時獲取圖像, 首先從每個攝像頭抓取一幀. 在抓取動作都結束后再恢復幀圖像.
釋放抓取源:
- cvReleaseCapture(&capture);
注意由設備抓取的圖像是由capture函數自動分配和釋放的. 不要試圖自己釋放它.
獲取/設定幀信息
獲取設備特性:
- cvQueryFrame(capture); // this call is necessary to get correct // capture properties
- int frameH = (int) cvGetCaptureProperty(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);
所有幀數似乎只與視頻文件有關. 用攝像頭時不對,奇怪!!!.
獲取幀信息:
- 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);
獲取所抓取幀在視頻序列中的位置, 從首幀開始按[毫秒]算. 或者從首幀開始從0標號, 獲取所抓取幀的標號. 或者取相對位置,首幀為0,末幀為1, 只對視頻文件有效.
設定所抓取的第一幀標號:
- // 從視頻文件相對位置0.9處開始抓取
- cvSetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO, (double)0.9);
只對從視頻文件抓取有效. 不過似乎也不成功!!!
存儲視頻文件
初始化視頻存儲器:
- CvVideoWriter *writer = 0;
- int isColor = 1;
- int fps = 25; // or 30
- int frameW = 640; // 744 for firewire cameras
- int frameH = 480; // 480 for firewire cameras
- writer = 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則將打開一個編碼選擇窗口(windows系統下).
存儲視頻文件:
- IplImage* img = 0;
- int nFrames = 50;
- for(i=0;i<nFrames;i++)
- {
- cvGrabFrame(capture); // 抓取幀
- img=cvRetrieveFrame(capture); // 恢復圖像
- cvWriteFrame(writer,img); // 將幀添加入視頻文件
- }
若想在抓取中查看抓取圖像, 可在循環中加入下列代碼:
- cvShowImage("mainWin", img);
- key=cvWaitKey(20); // wait 20 ms
若沒有20[毫秒]延遲,將無法正確顯示視頻序列.
釋放視頻存儲器:
- cvReleaseVideoWriter(&writer);