OpenCV 視頻與圖片序列相互轉換


我們在計算機視覺相關的實驗中都需要視頻與圖片序列之間相互轉換,在平時的實驗中,經常需要將視頻保存為一幀一幀的圖片,以獲取實驗結果;另一方面,很多標准的算法測試數據庫都是圖片序列(文件名以幀號+圖片擴展名),我們可能需要將其轉換為視頻,因此視頻與圖片之間的轉換是很常見的操作。在網上找到比較好的測試程序,方面將其封裝為函數,方便調用;另一方面,視頻轉圖片可以任意設定圖片輸出目錄,函數會自動創建相關目錄;圖片序列轉視頻可以設定更多的參數,也就可以更好的控制,而且可以自行設定視頻輸出的目錄,函數自動檢測並創建相關目錄。適合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;

感謝資源提供:http://blog.sina.com.cn/s/blog_4b0020f301011yqr.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM