OPENCV 矩陣操作

 

最近使用opencv+vs2008讀取攝像頭的時候,抓取圖像總是返回空。無解,在網上看到一個資料,轉載於此。

GEMM

通用矩陣乘法

void cvGEMM( const CvArr* src1, const CvArr* src2, double alpha, const CvArr* src3, double beta, CvArr* dst, int tABC=0 ); #define cvMatMulAdd( src1, src2, src3, dst ) cvGEMM( src1, src2, 1, src3, 1, dst, 0 ) #define cvMatMul( src1, src2, dst ) cvMatMulAdd( src1, src2, 0, dst )
src1
第一輸入數組
src2
第二輸入數組
src3
第三輸入數組 (偏移量),如果沒有偏移量,可以爲空( NULL) 。
dst
輸出數組
tABC
T操作標誌,可以是 0 或者下面列舉的值的組合:
CV_GEMM_A_T - 轉置 src1
CV_GEMM_B_T - 轉置 src2
CV_GEMM_C_T - 轉置 src3
例如, CV_GEMM_A_T+CV_GEMM_C_T 對應
alpha*src1T*src2 + beta*src3T

函數 cvGEMM 執行通用矩陣乘法:

dst = alpha*op(src1)*op(src2) + beta*op(src3), 這裏 op(X) 是 X 或者 XT

所有的矩陣應該有相同的數據類型和協調的矩陣大小。支持實數浮點矩陣或者複數浮點矩陣。

Transform

對數組每一個元素執行矩陣變換

void cvTransform( const CvArr* src, CvArr* dst, const CvMat* transmat, const CvMat* shiftvec=NULL );
src
輸入數組
dst
輸出數組
transmat
變換矩陣
shiftvec
可選偏移向量

函數 cvTransform 對數組 src 每一個元素執行矩陣變換並將結果存儲到 dst:

dst(I)=transmat*src(I) + shiftvec

或者

dst(I)k=sumj(transmat(k,j)*src(I)j) + shiftvec(k)

N-通道數組 src 的每一個元素都被視爲一個N元向量,使用一個 M×N 的變換矩陣 transmat 和偏移向量 shiftvec 把它變換到一個 M-通道的數組 dst 的一個元素中。 這裏可以選擇將偏移向量 shiftvec 嵌入到 transmat 中。這樣的話 transmat 應該是 M×N+1 的矩陣,並且最右邊的一列被看作是偏移向量 。

輸入數組和輸出數組應該有相同的位深(depth)和同樣的大小或者 ROI 大小。 transmat 和 shiftvec 應該是實數浮點矩陣。

該函數可以用來進行 ND 點集的幾何變換,任意的線性顏色空間變換,通道轉換等。

MulTransposed

計算數組和數組的轉置的乘積

void cvMulTransposed( const CvArr* src, CvArr* dst, int order, const CvArr* delta=NULL );
src
輸入矩陣
dst
目標矩陣
order
乘法順序
delta
一個可選數組, 在乘法之前從 src 中減去該數組。

函數 cvMulTransposed 計算 src 和它的轉置的乘積。

函數求值公式:

如果 order=0

dst=(src-delta)*(src-delta)T

否則

dst=(src-delta)T*(src-delta)

Trace

返回矩陣的跡

CvScalar cvTrace( const CvArr* mat );
mat
輸入矩陣

函數 cvTrace 返回矩陣mat的對角線元素的和。

tr(src) = mat(i,i)
  i  

Transpose

矩陣的轉置

void cvTranspose( const CvArr* src, CvArr* dst ); #define cvT cvTranspose
src
輸入矩陣
dst
目標矩陣

函數 cvTranspose 對矩陣 src 求轉置:

dst(i,j)=src(j,i)

注意,假設是複數矩陣不會求得複數的共軛。共軛應該是獨立的:查看的 cvXorS 例子代碼。

Det

返回矩陣的行列式值

double cvDet( const CvArr* mat );
mat
輸入矩陣

函數 cvDet 返回方陣 mat 的行列式值。對小矩陣直接計算,對大矩陣用高斯(GAUSSIAN)消去法。對於對稱正定(positive-determined)矩陣也可以用 SVD 函數來求,U=V=NULL ,然後用 w 的對角線元素的乘積來計算行列式。

Invert

查找矩陣的逆矩陣或僞逆矩陣

double cvInvert( const CvArr* src, CvArr* dst, int method=CV_LU ); #define cvInv cvInvert
src
輸入矩陣
dst
目標矩陣
method
求逆方法:
CV_LU -最佳主元選取的高斯消除法
CV_SVD - 奇異值分解法 (SVD)
CV_SVD_SYM - 正定對稱矩陣的 SVD 方法

函數 cvInvert 對矩陣 src 求逆並將結果存儲到 dst。

如果是 LU 方法該函數返回 src 的行列式值 (src 必須是方陣)。 如果是 0, 矩陣不求逆, dst 用 0 填充。

如果 SVD 方法該函數返回 src 的條件數的倒數(最小奇異值和最大奇異值的比值) ,如果 src 全爲 0 則返回0。 如果 src 是奇異的, SVD 方法計算一個僞逆矩陣。

Solve

求解線性系統或者最小二乘法問題

int cvSolve( const CvArr* src1, const CvArr* src2, CvArr* dst, int method=CV_LU );
src1
輸入矩陣
src2
線性系統的右部
dst
輸出解答
method
解決方法(矩陣求逆) :
CV_LU - 最佳主元選取的高斯消除法
CV_SVD - 奇異值分解法 (SVD)
CV_SVD_SYM - 對正定對稱矩陣的 SVD 方法

函數 cvSolve 解決線性系統或者最小二乘法問題 (後者用 SVD 方法可以解決):

\mbox{dst} = \arg \min_X |\mbox{src1}\cdot X-\mbox{src2}|

如果使用 CV_LU 方法。 如果 src1 是非奇異的,該函數則返回 1 ,否則返回 0 ,在後一種情況下 dst 是無效的。

SVD

對實數浮點矩陣進行奇異值分解

void cvSVD( CvArr* A, CvArr* W, CvArr* U=NULL, CvArr* V=NULL, int flags=0 );
A
M×N 的輸入矩陣
W
結果奇異值矩陣 (M×N 或者 N×N) 或者 向量 (N×1).
U
可選的左部正交矩陣 (M×M or M×N). 如果 CV_SVD_U_T 被指定,應該交換上面所說的行與列的數目。
V
可選右部正交矩陣(N×N)
flags
操作標誌; 可以是 0 或者下面的值的組合:
  • CV_SVD_MODIFY_A 通過操作可以修改矩陣 src1 。這樣處理速度會比較快。
  • CV_SVD_U_T 意味着會返回轉置矩陣 U ,指定這個標誌將加快處理速度。
  • CV_SVD_V_T 意味着會返回轉置矩陣 V ,指定這個標誌將加快處理速度。

函數 cvSVD 將矩陣 A 分解成一個對角線矩陣和兩個正交矩陣的乘積:

\mathbf{\it A=U W V^T}

這裏 W 是一個奇異值的對角線矩陣,它可以被編碼成奇異值的一維向量,U 和 V 也是一樣。所有的奇異值都是非負的並按降序存儲。(U 和 V 也相應的存儲)。

SVD 算法在數值處理上已經很穩定,它的典型應用包括:

  • 當 A 是一個方陣、對稱陣和正矩陣時精確的求解特徵值問題,例如, 當 A 時一個協方差矩陣時。在這種情況下 W 將是一個特徵值的的向量,並且 U=V是矩陣的特徵向量(因此,當需要計算特徵向量時 U 和 V 只需要計算其中一個就可以了) 。
  • 精確的求解病態線性系統。
  • 超定線性系統的最小二乘求解。上一個問題和這個問題都可以用指定 CV_SVD 的 cvSolve 方法。
  • 精確計算矩陣的不同特徵,如秩(非零奇異值的數目), 條件數(最大奇異值和最小奇異值的比例), 行列式值(行列式的絕對值等於奇異值的乘積).上述的所有這些值都不要求計算矩陣 U 和 V 。

SVBkSb

奇異值回代算法(back substitution)

void cvSVBkSb( const CvArr* W, const CvArr* U, const CvArr* V, const CvArr* B, CvArr* X, int flags );
W
奇異值矩陣或者向量
U
左正交矩陣 (可能是轉置的)
V
右正交矩陣 (可能是轉置的)
B
原始矩陣 A 的僞逆的乘法矩陣。這個是可選參數。如果它被省略則假定它是一個適當大小的單位矩陣(因此 x 將是 A 的僞逆的重建).。
X
目標矩陣: 奇異值回代算法的結果
flags
操作標誌, 和剛剛討論的 cvSVD 的標誌一樣。

函數 cvSVBkSb 爲被分解的矩陣 A 和矩陣 B 計算回代逆(back substitution) (參見 cvSVD 說明) :

X=V*W-1*UT*B

這裏

W-1(i,i)=1/W(i,i) 如果 W(i,i) > epsilon•sumiW(i,i),
否則:0.

epsilon 是一個依賴於矩陣數據類型的的很小的數。該函數和 cvSVD 函數被用來執行 cvInvert 和 cvSolve, 用這些函數 (svd & bksb)的原因是初級函數(low-level)函數可以避免高級函數 (inv & solve) 計算中內部分配的臨時矩陣。

EigenVV

計算對稱矩陣的特徵值和特徵向量

void cvEigenVV( CvArr* mat, CvArr* evects, CvArr* evals, double eps=0 );
mat
輸入對稱方陣。在處理過程中將被改變。
evects
特徵向量輸出矩陣, 連續按行存儲
evals
特徵值輸出矩陣,按降序存儲(當然特徵值和特徵向量的排序是同步的)。
eps
對角化的精確度 (典型地, DBL_EPSILON=≈10-15 就足夠了)。

函數 cvEigenVV 計算矩陣 A 的特徵值和特徵向量:

mat*evects(i,:)' = evals(i)*evects(i,:)' (在 MATLAB 的記法)

矩陣 A 的數據將會被這個函數修改。

目前這個函數比函數 cvSVD 要慢,精確度要低, 如果已知 A 是正定的,(例如, 它是一個協方差矩陣), 它通常被交給函數 cvSVD 來計算其特徵值和特徵向量,尤其是在不需要計算特徵向量的情況下

CalcCovarMatrix

計算向量集合的協方差矩陣

void cvCalcCovarMatrix( const CvArr** vects, int count, CvArr* cov_mat, CvArr* avg, int flags );
vects
輸入向量。他們必須有同樣的數據類型和大小。這個向量不一定非是一維的,他們也可以是二維(例如,圖像)等等。
count
輸入向量的數目
cov_mat
輸出協方差矩陣,它是浮點型的方陣。
avg
輸入或者輸出數組 (依賴於標記“flags”) - 輸入向量的平均向量。
flags
操作標誌,下面值的組合:
CV_COVAR_SCRAMBLED - 輸出協方差矩陣按下面計算:
scale * [vects[0] − avg,vects[1] − avg,...]T * [vects[0] − avg,vects[1] − avg,...], 即協方差矩陣是 count×count. 這樣一個不尋常的矩陣用於一組大型向量的快速PCA方法(例如, 人臉識別的 EigenFaces 技術)。這個混雜("scrambled")矩陣的特徵值將和真正的協方差矩陣的特徵值匹配,真正的特徵向量可以很容易的從混雜("scrambled")協方差矩陣的特徵向量中計算出來。
CV_COVAR_NORMAL - 輸出協方差矩陣被計算成:
scale * [vects[0] − avg,vects[1] − avg,...] * [vects[0] − avg,vects[1] − avg,...]T, 也就是說, cov_mat 將是一個和每一個輸入向量的元素數目具有同樣線性大小的通常協方差矩陣。 CV_COVAR_SCRAMBLED 和 CV_COVAR_NORMAL 只能同時指定其中一個。
CV_COVAR_USE_AVG - 如果這個標誌被指定, 該函數將不會從輸入向量中計算 avg ,而是用過去的 avg 向量,如果 avg 已經以某種方式計算出來了這樣做是很有用的。或者如果協方差矩陣是部分計算出來的 - 倘若這樣, avg 不是輸入向量的子集的平均值,而是整個集合的平均向量。
CV_COVAR_SCALE - 如果這個標誌被指定,協方差矩陣被縮放了。 the covariation matrix is scaled.在 "normal" 模式下縮放比例是 1./count, 在 "scrambled" 模式下縮放比例是每一個輸入向量的元素總和的倒數。 缺省地(如果沒有指定標誌) 協方差矩陣不被縮放 (scale=1)。

函數 cvCalcCovarMatrix 計算輸入向量的協方差矩陣和平均向量。該函數可以被運用到主成分分析中(PCA),以及馬氏距離(Mahalanobis distance)比較向量中等等。

Mahalanobis

計算兩個向量之間的馬氏距離(Mahalanobis distance)

double cvMahalanobis( const CvArr* vec1, const CvArr* vec2, CvArr* mat );
vec1
第一個一維輸入向量
vec2
第二個一維輸入向量
mat
協方差矩陣的逆矩陣

函數 cvMahalanobis 計算兩個向量之間的加權距離,其返回結果是:

d(vec1,vec2)=\sqrt{ \sum_{i,j} \{mat(i,j)*(vec1(i)-vec2(i))*(vec1(j)-vec2(j))\} }

協方差矩陣可以用函數cvCalcCovarMatrix 計算出來,逆矩陣可以用函數 cvInvert 計算出來 (CV_SVD 方法是一個比較好的選擇, 因爲矩陣可能是奇異的).

CalcPCA

對一個向量集做PCA變換

void cvCalcPCA( const CvArr* data, CvArr* avg, CvArr* eigenvalues, CvArr* eigenvectors, int flags );
data
輸入數據,每個向量是單行向量(CV_PCA_DATA_AS_ROW)或者單列向量(CV_PCA_DATA_AS_COL).
avg
平均向量,在函數內部計算或者由調用者提供
eigenvalues
輸出的協方差矩陣的特徵值
eigenvectors
輸出的協方差矩陣的特徵向量(也就是主分量),每個向量一行
flags
操作標誌,可以是以下幾種方式的組合:
CV_PCA_DATA_AS_ROW - 向量以行的方式存放(也就是說任何一個向量都是連續存放的)
CV_PCA_DATA_AS_COL - 向量以列的方式存放(也就是說某一個向量成分的數值是連續存放的)
(上面兩種標誌是互相排斥的)
CV_PCA_USE_AVG - 使用預先計算好的平均值

該函數對某個向量集做PCA變換.它首先利用cvCalcCovarMatrix計算協方差矩陣然後計算協方差矩陣的特徵值與特徵向量.輸出的特徵值/特徵向量的個數小於或者等於MIN(rows(data),cols(data)).

ProjectPCA

把向量向某個子空間投影

void cvProjectPCA( const CvArr* data, const CvArr* avg, const CvArr* eigenvectors, CvArr* result )
data
輸入數據,每個向量可以是單行或者單列
avg
平均向量.要麼它是單行向量那麼意味着輸入數據以行數據的形式存放,要麼就是單列向量,那麼就意味着那麼輸入向量就是以列的方式存放.
eigenvectors
特徵向量(主分量),每個向量一行.
result
輸出的分解係數矩陣,矩陣的行數必須與輸入向量的個數相等,矩陣的列數必須小於特徵向量的行數.

該函數將輸入向量向一個正交系(eigenvectors)投影.在計算點乘之前,輸入向量要減去平均向量:

result(i,:)=(data(i,:)-avg)*eigenvectors' // for CV_PCA_DATA_AS_ROW layout.

BackProjectPCA

根據投影係數重構原來的向量

void cvBackProjectPCA( const CvArr* proj, const CvArr* avg, const CvArr* eigenvects, CvArr* result );
proj
輸入數據,與cvProjectPCA裏面的格式一致
avg
平均向量.如果它是單行向量,那麼意味着輸出向量是以行的方式存放.否則就是單列向量,那麼輸出向量就是以列的方式存放.
eigenvectors
特徵向量(主分量),每個向量一行.
result
輸出的重構出來的矩陣

該函數根據投影係數重構原來的向量:

result(i,:)=proj(i,:)*eigenvectors + avg // for CV_PCA_DATA_AS_ROW layout

矩陣操作

分配釋放矩陣空間

  • 綜述:
    • OpenCV有針對矩陣操作的C語言函數. 許多其他方法提供了更加方便的C++接口,其效率與OpenCV一樣.
    • OpenCV將向量作爲1維矩陣處理.
    • 矩陣按行存儲,每行有4字節的校整.
  • 分配矩陣空間:
    CvMat* cvCreateMat(int rows, int cols, int type);
     
       type: 矩陣元素類型. 格式爲CV_<bit_depth>(S|U|F)C<number_of_channels>.  
       例如: CV_8UC1 表示8位無符號單通道矩陣, CV_32SC2表示32位有符號雙通道矩陣.
     
       例程:
       CvMat* M = cvCreateMat(4,4,CV_32FC1);
  • 釋放矩陣空間:
    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); // 這裏似乎有問題,不成功

存取矩陣元素

  • 假設需要存取一個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 -> 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 返回時被轉置(若沒有轉置標號,則有問題不成功!!!).

視頻序列操作

從視頻序列中抓取一幀

  • 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);
發佈了49 篇原創文章 · 獲贊 6 · 訪問量 23萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章