利用OpenCV進行【視頻的讀取】與【保存視頻文件或者圖像】源碼!~
爲了能夠更好的支持AVI視頻的讀取,請安裝K-Lite Codec Pack Full 3.9.3 Beta
下載地址:http://dl.pconline.com.cn/html_2/1/124/id=6563&pn=0.html
#include <afx.h>
#include <iostream>
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
using namespace std;
/////////////////////////////////////////////////////////
//作者:Flobert_Young
//日期:2008-05-22
//說明:
// 需要配置OpenCV的開發環境,並且一定要確保當前Project里加入了cv.lib cxcore.lib highgui.lib庫
//鏈接錯誤解決方法:
// 編譯時出現unresolved external symbol __endthreadex 的處理方法
// 菜單 Project->Settings... 在 C/C++ 頁,
// 在 Category 下拉框裏選擇 Code Generation,
// 然後在 Use run-time library 裏選擇
// Debug Multithreaded ( Debug 版本時用 )
// 或者 Multithreaded ( release 版本時用).
/////////////////////////////////////////////////////////
enum CaptureCase
{
CAP_FROM_CAM = 0,
CAP_FROM_VIDEO = 1,
};
enum PlayVideoCase
{
FRAME_BY_FRAME = 0,
FRAME_BY_INDEX = 1,
};
//////////////////////////////////////
//函數聲明
int FrameByFrame(CvVideoWriter * pVideoWriter,IplImage *pFrame,bool bSave,
CvCapture * pCapture,char *pVideoSaveName,int nWaitKeyTime);
int FrameByIndex(CvCapture * pCapture,IplImage *pFrame,
int cap_prop,int cap_prop_value,
CString strSaveImagePath);
//////////////////////////////////////
//主函數部分
int main()
{
int ret = 0;
bool bErr = 0;
bool bSave = 0; //0 - 不保存視頻文件;1 - 保存視頻文件
CaptureCase cap_case = CAP_FROM_VIDEO; //設置成從視頻文件中獲取圖像
PlayVideoCase play_case = FRAME_BY_FRAME; //設置成一幀一幀的播放視頻文件
int nWaitKeyTime = 40; //顯示圖像所間隔的時間,以“毫秒”爲單位
//////////////////////////////////////
//變量聲明
CvCapture * pCapture = NULL; //用於在視頻中捕獲圖像
char szVideoFileName[] = "C://電影.AVI"; //!將打開的視頻文件名設置成"C://1.mpg"
char szVideoSaveName[] = "C://VideoSave.avi"; //!將保存視頻文件的名字設置成"C://VideoSave.avi"
CString strSaveImagePath = "C://"; //!保存圖片的目錄名
CvVideoWriter * pVideoWriter = NULL; //用於保存視頻文件
IplImage * pFrame = NULL;
IplImage * pImage = NULL;
switch(cap_case)
{
case CAP_FROM_CAM:
//函數cvCaptureFromCAM()參數說明:
//要使用的攝像頭索引。如果只有一個攝像頭或者用哪個攝像頭也無所謂,那使用參數-1應該便可以。
pCapture = cvCaptureFromCAM(-1); //和函數cvCreateCameraCapture()有什麼區別???
if(NULL==pCapture) //打開攝像頭
{
cout<<"ERROR: 攝像頭讀取失敗!"<<endl;
bErr = 1;
}
break;
case CAP_FROM_VIDEO: //打開視頻文件
pCapture = cvCaptureFromFile(szVideoFileName); //和函數cvCreateFileCapture()有什麼區別???
if(NULL==pCapture)
{
cout<<"ERROR: 視頻文件讀取失敗!"<<endl;
bErr = 1;
}
break;
}
if(!bErr)
{
switch(play_case)
{
case FRAME_BY_FRAME:
FrameByFrame(pVideoWriter,pFrame,bSave,pCapture,szVideoFileName,nWaitKeyTime);
break;
case FRAME_BY_INDEX:
//在窗口上顯示視頻的61%部分的那一幀圖像
int cap_prop_value = 61;
FrameByIndex(pCapture,pFrame,CV_CAP_PROP_POS_AVI_RATIO,cap_prop_value,strSaveImagePath);
break;
}
}
char ch;
cin>>ch;
return ret;
}
int FrameByFrame(CvVideoWriter * pVideoWriter,IplImage *pFrame,bool bSave,
CvCapture * pCapture,char *pVideoSaveName,int nWaitKeyTime)
{
int ret = 0;
/****************************************/
///////////////////////////
//1.逐幀讀取視頻
int nCurFrameIndex = 0;
cvNamedWindow("Frame_By_Frame",1);
//在圖像窗口左上角顯示“Current Frame: **”字符串
CString strFrameString;
CvFont font;
cvInitFont( &font,CV_FONT_HERSHEY_SIMPLEX,0.5,0.5,0,2,8 );
//創建視頻文件寫入器
//第二個參數fourcc - 四個字符用來表示壓縮幀的codec
//例如,CV_FOURCC('P','I','M','1')是MPEG-1 codec,
//CV_FOURCC('M','J','P','G')是motion-jpeg codec等。
//在Win32下,如果傳入參數-1,可以從一個對話框中選擇壓縮方法和壓縮參數。
//這裏是按20幀/s進行寫入視頻文件的,但是當右鍵"C://VideoSave.avi"屬性 -> 摘要,
//發現“持續時間: 0:00:02 幀速率: 500幀/秒”???
//如果改成30幀/s,則發現屬性改爲“持續時間: 0:00:01 幀速率: 750幀/秒”???
if(1==bSave)
{
pVideoWriter = cvCreateVideoWriter(pVideoSaveName,-1,20,cvSize(640,480),1);
}
if((NULL!=pVideoWriter&&bSave)||(!bSave))
{
while(pFrame = cvQueryFrame(pCapture))
{
if(1==bSave)
{
//將獲取的視頻文件一幀一幀的寫入要保存的視頻文件中
cvWriteFrame(pVideoWriter,pFrame);
}
nCurFrameIndex++;
strFrameString.Format("Current Frame: %d",nCurFrameIndex);
cvPutText( pFrame,strFrameString,cvPoint( 5,pFrame->height-15 ),&font,cvScalar( 0,255,0 ) );
cvShowImage("Frame_By_Frame",pFrame);
if(0==bSave) //如果是保存視頻時,則加快顯示速度
{
cvWaitKey(nWaitKeyTime);
}
else
{
cvWaitKey(10); //如果選擇保存視頻時,好像不能夠正常顯示圖像???
}
}
if(1==bSave)
{
//釋放視頻寫入器
cvReleaseVideoWriter(&pVideoWriter);
}
cvDestroyWindow("Frame_By_Frame");
cvReleaseCapture(&pCapture);
}
else
{
cout<<"ERROR:創建CvVideoWriter * 失敗!"<<endl;
}
/****************************************/
ret = 1;
return ret;
}
int FrameByIndex(CvCapture * pCapture,IplImage *pFrame,int cap_prop,int cap_prop_value,
CString strSaveImagePath)
{
int ret = 0;
/****************************************/
///////////////////////////
//2.讀取第i幀視頻
cvNamedWindow("FrameIndex_i",1);
//目前這個函數對視頻文件只支持:
//CV_CAP_PROP_POS_MSEC, CV_CAP_PROP_POS_FRAMES, CV_CAP_PROP_POS_AVI_RATIO
switch(cap_prop)
{
case CV_CAP_PROP_POS_MSEC:
//讀取視頻中第cap_prop_value秒的圖像
cvSetCaptureProperty(pCapture,CV_CAP_PROP_POS_MSEC,cap_prop_value);
break;
case CV_CAP_PROP_POS_FRAMES:
//讀取視頻中第cap_prop_value幀的圖像
cvSetCaptureProperty(pCapture,CV_CAP_PROP_POS_FRAMES,cap_prop_value);
break;
case CV_CAP_PROP_POS_AVI_RATIO:
//讀取視頻中cap_prop_value%處的圖像
double ratio = cap_prop_value/100.0; //100.0是爲了將除法的結果轉化成“浮點型”
cvSetCaptureProperty(pCapture,CV_CAP_PROP_POS_AVI_RATIO,ratio);
break;
}
if(pFrame = cvQueryFrame(pCapture))
{
//保存當前圖像
CString strSaveImageName;
CString strTmp;
strTmp.Format("SaveImage_%d.bmp",cap_prop_value);
strSaveImageName = strSaveImagePath + strTmp;
cvSaveImage(strSaveImageName,pFrame);
cvShowImage("FrameIndex_i",pFrame);
cvWaitKey(-1);
}
cvDestroyWindow("FrameIndex_i");
cvReleaseCapture(&pCapture);
/****************************************/
ret = 1;
return ret;
}