opencv進行圖像序列與視頻的轉換

常見的視頻跟蹤數據庫,如:

Visual Tracking Benchmark:http://cvlab.hanyang.ac.kr/tracker_benchmark/datasets.html,給出的跟蹤算法測試視頻多爲圖片序列,附加待跟蹤目標在每一幀視頻中的標定位置,即groundtruth,我們可以利用opencv進行視頻與圖像序列間的轉換,由於opencv不會自動創建目錄,所以整個程序分爲3個部分,多級目錄的自動建立,視頻轉圖片序列函數,圖片序列轉視頻函數。

int recursive_mkdir( char *dir );//自動創建多級目錄
int ImageToVideo(char* outDir,char* videoName,char* inputDir,int startFrame,int endFrame, int imgW,
    int imgH,char* imgExt,double fps,int isColor,int fourcc);//圖片序列轉化爲視頻
int  VideoToImage(char* videoName,char* outDir,char* imgExt,int maxFrameCount);//視頻轉化爲圖片序列

自動創建多級目錄(從根目錄開始):

int recursive_mkdir( char *dir )
{
	 //分解路徑名E:\\AA\\BB\\CC\\
	 //
	 std::string str = dir;
	 int index = 0;
	 int i = 0;
	 while(1)
	 {
		  std::string::size_type pos = str.find("\\",index);
		  std::string str1;
		  str1 = str.substr(0,pos);
		  if( pos != -1 && i > 0 )
		  {
			   if (_access(str1.c_str(),0)==-1)
			   {
				   _mkdir(str1.c_str());
			   }
		  }
		  if( pos==-1 ) break;
		  i ++;
		  index = pos+1;
	 }
	 return 0;
}


圖片序列轉換爲視頻:

//將圖片序列轉換爲視頻,返回視頻幀數(輸入輸出目錄,輸入圖片長寬,起始幀與結束幀,擴展名等)
int ImageToVideo(char* outDir,char* videoName,char* inputDir,int startFrame,int endFrame, int imgW,int imgH,char* imgExt,double fps=24,int isColor=1,int fourcc=CV_FOURCC('X','V','I','D'))
{       
    //判斷輸入文件夾是否存在
	if (_access(inputDir,0)==-1)
	{
		std::cout<<"the input directory does not exist!"<<std::endl;
		return 0;
	}
    //判斷輸出文件夾是否創建 若沒有則創建;若爲NULL則默認當前工作目錄
    char fullVideoName[255];//輸出視頻的完整文件名:路徑+文件名
    strcpy_s(fullVideoName,"");
	if (outDir==NULL)
	{
		sprintf_s(fullVideoName,"%s",videoName);//把videoName打印成一個字符串保存在fullVideoName 中 
	}
	else
	{
		if (_access(outDir,0)==-1)
			{
				recursive_mkdir(outDir);
			}
		sprintf_s(fullVideoName,"%s%s",outDir,videoName);//將字符串outDir和videoName連接起來,打印,保存在fullVideoName中
	}

	int frameCount=0;
	CvVideoWriter *pWriter=NULL;
	CvSize size=cvSize(imgW,imgH);
	pWriter=cvCreateVideoWriter(videoName,fourcc,fps,size,isColor);//CREATE WRITER
        
	IplImage *pImg=NULL;
	char cur_fn[255];//表示某張圖片的路徑
	const int length=4; //length of the picure name
	
	while(startFrame<=endFrame)
	{
		strcpy_s(cur_fn,"");
		char current_frame[length+1];
		itoa(startFrame,current_frame,10);
		int t=length-strlen(current_frame);
		char current_frame2[length+1];
		sprintf(current_frame2,"%0*d%s", length-strlen(current_frame), 0, current_frame);
		sprintf_s(cur_fn,"%s%s%s",inputDir,current_frame2,imgExt);//need to change  
		pImg=cvLoadImage(cur_fn,isColor);
		if (!pImg)    
		{
		std::cout<<"can't open an image file"<<std::endl;
		return frameCount;
		}
		cvWriteFrame(pWriter,pImg);
		cvWaitKey(1);
		std::cout<<"Write frame "<<startFrame<<std::endl;
		startFrame++;
	
		cvReleaseImage(&pImg);
		frameCount++;
	}
	cvReleaseVideoWriter(&pWriter);
	rename(videoName,fullVideoName);//移動文件到指定文件夾
	return  frameCount;
}


視頻轉圖片序列:

//視頻轉爲圖片序列(輸入輸出目錄,擴展名,輸出圖片總張數)
int  VideoToImage(char* videoName,char* outDir,char* imgExt,int maxFrameCount)
{
	CvCapture *cap= cvCaptureFromFile(videoName);
	if (cap==NULL)
	{
		return 0;
	}
	//保存圖片的文件夾路徑一定要有,因爲OpenCV不會自動創建文件夾
	if (_access(outDir,0)==-1)
	{
		recursive_mkdir(outDir);
		std::cout<<"the ouput directory does not exist, and the have been created autonomously!"<<std::endl;
	}
	char cur_fn[255];//保存當前幀所得圖片的文件名
	IplImage* pImg=NULL;
	int frame=0;
	while((pImg=cvQueryFrame(cap))!=NULL&&(frame<maxFrameCount))
	{               
		frame++;
		strcpy_s(cur_fn,"");
		sprintf_s(cur_fn,"%s%d%s",outDir,frame,imgExt);//這裏的設置適合形如 123.jpg 124.jpg的圖片序列
		cvSaveImage(cur_fn,pImg,NULL);
	}	

	//cvReleaseImage(&pImg);
	cvReleaseCapture(&cap);
	return frame;
}


主函數:

#include <string>
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <direct.h>//for mk_dir
#include <io.h>//for _acess()
#include <string>
#define ImageToVideoFlag 

int recursive_mkdir( char *dir );//自動創建多級目錄
int ImageToVideo(char* outDir,char* videoName,char* inputDir,int startFrame,int endFrame, int imgW,
    int imgH,char* imgExt,double fps,int isColor,int fourcc);//圖片序列轉化爲視頻
int  VideoToImage(char* videoName,char* outDir,char* imgExt,int maxFrameCount);//視頻轉化爲圖片序列

 int main(int argc, char** argv)
 {	
#ifdef ImageToVideoFlag
	//圖片轉視頻F:\carrdisp_test\origin
	char* inputDir="img_input\\";
	char* videoName="david.mpg";
	char* outDir="E:\\video_output\\";

	//need to change according to your own picture sequences
	int frames=ImageToVideo(outDir,videoName,inputDir,1,770,320,240,".jpg",24,1,CV_FOURCC('X','V','I','D'));
	//int frames=ImageToVideo(outDir,videoName,inputDir,1,770,320,240,".jpg",24,1,CV_FOURCC('M','J','P','G'));
	std::cout<<"total frames "<<frames<<" have been write to video."<<std::endl;
		
	system("pause");
	return 0;
#else
	//視頻轉圖片
	char* videoName1="pedestrian1.mpg";
	char* outDir1="E:\\output_Imgseq\\";
	int images=VideoToImage(videoName1,outDir1,".jpg",200);
	std::cout<<"total frames have been extracted from video."<<std::endl;
	system("pause");
#endif
 }


注意事項:

1.主程序中若是視頻轉圖片序列,請配置自己的視頻輸入路徑(若只是配置文件名,請確保視頻文件在程序工程目錄中)和圖片序列輸出路徑,輸出路徑以根目錄開始(E:\\)。

2.rename函數將文件移入指定文件夾,但是若文件夾中已有同名文件,則不會移動。

3.圖片轉視頻時,可自行選擇輸出視頻的後綴名,但是注意opencv的視頻寫入編碼CV_FOURCC('X','V','I','D'),CV_FOURCC(’P’,’I’,’M’,’1’),CV_FOURCC(’M’,’J’,’P’,’G’)等,可能會與某視頻後綴名不匹配,造成視頻編解碼問題,無法讀取。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章