我們在計算機視覺相關的實驗中都需要視頻與圖片序列之間相互轉換,在平時的實驗中,經常需要將視頻保存為一幀一幀的圖片,以獲取實驗結果;另一方面,很多標准的算法測試數據庫都是圖片序列(文件名以幀號+圖片擴展名),我們可能需要將其轉換為視頻,因此視頻與圖片之間的轉換是很常見的操作。在網上找到比較好的測試程序,一方面將其封裝為函數,方便調用;另一方面,視頻轉圖片可以任意設定圖片輸出目錄,函數會自動創建相關目錄;圖片序列轉視頻可以設定更多的參數,也就可以更好的控制,而且可以自行設定視頻輸出的目錄,函數自動檢測並創建相關目錄。適合windows平台+OpenCV;
代碼如下:
View Code
1 // ImgToVideo_test.cpp : Defines the entry point for the console application. 2 // 3 4 #include "stdAfx.h" 5 #include <cv.h> 6 #include <highgui.h> 7 #include <iostream> 8 #include <direct.h>//for mk_dir 9 #include <io.h>//for _acess() 10 #include <string> 11 12 int recursive_mkdir( char *dir );//創建多級目錄 13 int ImageToVideo(char* outDir,char* videoName,char* inputDir,int startFrame,int endFrame, int imgW, 14 int imgH,char* imgExt,double fps,int isColor,int fourcc);//圖片序列轉化為視頻 15 int VideoToImage(char* videoName,char* outDir,char* imgExt,int maxFrameCount);//視頻轉化為圖片序列 16 17 18 int main(int argc, char** argv) 19 { 20 //圖片轉視頻F:\carrdisp_test\origin 21 char* inputDir="F:\\carrdisp_test1\\colorfore\\"; 22 char* videoName="carrdisp_clofr.avi"; 23 char* outDir="F:\\carrdisp_test1\\colorfore\\"; 24 int frames=ImageToVideo(outDir,videoName,inputDir,2,308,448,336,"_Fr.jpg",24,1,CV_FOURCC('X','V','I','D')); 25 std::cout<<"total frames "<<frames<<" have been write to video."<<std::endl; 26 int p; 27 std::cin>>p; 28 29 return 0; 30 } 31 32 //將圖片序列轉換為視頻,返回視頻幀數 33 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')) 34 { 35 //判斷輸入文件夾是否存在 36 if (_access(inputDir,0)==-1) 37 { 38 std::cout<<"the input directory does not exist!"<<std::endl; 39 return 0; 40 } 41 //判斷輸出文件夾是否創建 若沒有則創建;若為NULL則默認當前工作目錄 42 char fullVideoName[255];//輸出視頻的完整文件名:路徑+文件名 43 strcpy_s(fullVideoName,""); 44 if (outDir==NULL) 45 { 46 sprintf_s(fullVideoName,"%s",videoName);//把videoName打印成一個字符串保存在fullVideoName 中 47 } 48 else 49 { 50 if (_access(outDir,0)==-1) 51 { 52 recursive_mkdir(outDir); 53 } 54 sprintf_s(fullVideoName,"%s%s",outDir,videoName);//將字符串outDir和videoName連接起來,打印,保存在fullVideoName中 55 } 56 int frameCount=0; 57 CvVideoWriter *pWriter=NULL; 58 CvSize size=cvSize(imgW,imgH); 59 pWriter=cvCreateVideoWriter(videoName,fourcc,fps,size,isColor);//CREATE WRITER 60 61 IplImage *pImg=NULL; 62 char cur_fn[255];//表示某張圖片的路徑 63 while(startFrame<=endFrame) 64 { 65 strcpy_s(cur_fn,""); 66 sprintf_s(cur_fn,"%s%d%s",inputDir,startFrame,imgExt);//need to change 67 pImg=cvLoadImage(cur_fn,isColor); 68 if (!pImg) 69 { 70 std::cout<<"can't open an image file"<<std::endl; 71 return frameCount; 72 } 73 cvWriteFrame(pWriter,pImg); 74 cvWaitKey(1); 75 std::cout<<"Write frame "<<startFrame<<std::endl; 76 startFrame++; 77 cvReleaseImage(&pImg); 78 frameCount++; 79 } 80 cvReleaseVideoWriter(&pWriter); 81 rename(videoName,fullVideoName);//移動文件到指定文件夾 82 return frameCount; 83 } 84 //將視頻轉換為圖片序列 返回由視頻分解得到的圖片總幀數 目前OpenCV只支持AVI格式 因此使用之前需要 85 //將視頻轉化問AVI格式 86 87 int VideoToImage(char* videoName,char* outDir,char* imgExt,int maxFrameCount) 88 { 89 CvCapture *cap= cvCaptureFromFile(videoName); 90 if (cap==NULL) 91 { 92 return 0; 93 } 94 //保存圖片的文件夾路徑一定要有,因為OpenCV不會自動創建文件夾 95 if (_access(outDir,0)==-1) 96 { 97 recursive_mkdir(outDir); 98 std::cout<<"the ouput directory does not exist, and the have been created autonomously!"<<std::endl; 99 } 100 char cur_fn[255];//保存當前幀所得圖片的文件名 101 IplImage* pImg=NULL; 102 int frame=0; 103 while((pImg=cvQueryFrame(cap))!=NULL&&(frame<maxFrameCount)) 104 { 105 frame++; 106 strcpy_s(cur_fn,""); 107 sprintf_s(cur_fn,"%s%d%s",outDir,frame,imgExt);//這里的設置適合形如 123.jpg 124.jpg的圖片序列 108 cvSaveImage(cur_fn,pImg,NULL); 109 } 110 cvReleaseImage(&pImg); 111 cvReleaseCapture(&cap); 112 return frame; 113 } 114 115 116 //該函數借鑒了網上資料,自動創建多級目錄 117 int recursive_mkdir( char *dir ) 118 { 119 //分解路徑名E:\\AA\\BB\\CC\\ 120 // 121 std::string str = dir; 122 int index = 0; 123 int i = 0; 124 while(1) 125 { 126 std::string::size_type pos = str.find("\\",index); 127 std::string str1; 128 str1 = str.substr(0,pos); 129 if( pos != -1 && i > 0 ) 130 { 131 if (_access(str1.c_str(),0)==-1) 132 { 133 _mkdir(str1.c_str()); 134 } 135 } 136 if( pos==-1 ) 137 { 138 break; 139 } 140 i ++; 141 index = pos+1; 142 } 143 return 0; 144 }
上面程序在VS2010+opencv2.3.1+windows XP環境下測試通過,使用時注意設置好開始幀,結束幀,圖片格式即可。本人圖片目錄如:
F:\carrdisp_test1\colorfore\2_Fr.jpg
其中只調用了圖片序列寫為視頻的函數,另一個函數調用方法相似,如下舉例:
View Code
//視頻轉圖片 char* videoName1="E:\\VIDEOS\\TEST\\Videos\\woman.avi"; char* outDir1="E:\\VIDEOS\\TEST\\Sequences\\WoemenSequence\\"; int images=VideoToImage(videoName1,outDir1,".jpg",200); std::cout<<"total frames have been extracted from video."<<std::endl; int p; std::cin>>p;
