在平時的實驗中,經常需要將視頻保存為一幀一幀的圖片,以獲取實驗結果;另一方面,很多標准的算法測試數據庫都是圖片序列(文件名以幀號+圖片擴展名),我們可能需要將其轉換為視頻,因此視頻與圖片之間的轉換是很常見的操作;以下分享一下自己平時編寫和使用的兩段很簡單但是實用的代碼;
(由於HTML顯示的原因,下面那些單引號全部是雙引號)
1.將圖片轉換為視頻
int isColor=1;//圖片是否為彩色
double fps=15;//幀率 按照需求設置
int imgW=352;//圖片寬度
int imgH=288;//圖片高度
char* flieName="videoname.avi";//保存的視頻文件名
int startFrame=0;//圖片開始幀號,這樣設計主要是因為實驗中可能只需要圖片的一部分幀序列
int endFrame=128;//同上
char cur_fn[255];//
char* prefix="E:\\image_sequences\\";//圖片序列的路徑
char* ext=".jpg";//序列圖片后綴名
CvSize size=cvSize(imgW,imgH);
pWriter=cvCreateVideoWriter(flieName,CV_FOURCC('X','V','I','D'),fps,size,isColor);//OpenCV 庫函數,創建視頻寫入器
IplImage *pImg=NULL;
while(startFrame<=endFrame)
{
strcpy(cur_fn,"");
sprintf(cur_fn,"%s%d%s",prefix,startFrame,ext);//這里的設置適合形如 123.jpg 124.jpg的圖片序列
pImg=cvLoadImage(cur_fn,isColor);
if (!pImg)
{
std::cout<<"can't open file"<<std::endl;
return 0;
}
cvWriteFrame(pWriter,pImg);
cvWaitKey(1);
std::cout<<"Write frame "<<startFrame<<std::endl;
startFrame++;
cvReleaseImage(&pImg);
}
cvReleaseVideoWriter(&pWriter);//記得用完 釋放資源 否則會運行失敗
2.將視頻轉換為圖片
這個就比較簡單了
char* vedio="videoname.avi";//視頻文件路徑
CvCapture *cap= cvCaptureFromFile(vedio);
if (cap==NULL)
{
return 0;
}
char cur_fn[255];//圖片文件名
char* ext=".jpg";//圖片格式
char* prefix="e:\\test\\";//保存圖片的文件夾路徑 一定要有,因為OpenCV不會自動創建文件夾
IplImage* pImg=NULL;
int frame=0;
while((pImg=cvQueryFrame(cap))!=NULL)
{
frame++;
strcpy(cur_fn,"");
sprintf(cur_fn,"%s%d%s",prefix,frame,ext);//這里的設置適合形如 123.jpg 124.jpg的圖片序列
cvSaveImage(cur_fn,pImg,NULL);
cvReleaseImage(&pImg);
}
=================================================================================
引言
我們在計算機視覺相關的實驗中都需要視頻與圖片序列之間相互轉換,上次簡單了寫了這兩種操作是如何實現的(http://blog.sina.com.cn/s/blog_4b0020f301010qcz.html),現在將其功能完善:一方面將其封裝為函數,方便調用;另一方面,視頻轉圖片可以任意設定圖片輸出目錄,函數會自動創建相關目錄;圖片序列轉視頻可以設定更多的參數,也就可以更好的控制,而且可以自行設定視頻輸出的目錄,函數自動檢測並創建相關目錄
適合windows平台+OpenCV;
需要引入包含文件:
#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <direct.h>//for mk_dir
#include <io.h>//for _acess()
#include <string>
三個主要的功能函數
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 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('D','I','V','X'))
{
//判斷輸入文件夾是否存在
if (_access(inputDir,0)==-1)
{
std::cout<<"the input directory does not exist!"<<std::endl;
return 0;
}
//判斷輸出文件夾是否創建若沒有則創建;若為NULL則默認當前工作目錄
char fullVideoName[255];//輸出視頻的完整文件名:路徑+文件名
strcpy(fullVideoName,"");
if (outDir==NULL)
{
sprintf(fullVideoName,"%s",videoName);
}
else
{
if (_access(outDir,0)==-1)
{
recursive_mkdir(outDir);
}
sprintf(fullVideoName,"%s%s",outDir,videoName);
}
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];//表示某張圖片的路徑
while(startFrame<=endFrame)
{
strcpy(cur_fn,"");
sprintf(cur_fn,"%s%d%s",inputDir,startFrame,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;
}
//將視頻轉換為圖片序列 返回由視頻分解得到的圖片總幀數 目前OpenCV只支持AVI格式 因此使用之前需要
//將視頻轉化問AVI格式
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(cur_fn,"");
sprintf(cur_fn,"%s%d%s",outDir,frame,imgExt);//這里的設置適合形如 123.jpg 124.jpg的圖片序列
cvSaveImage(cur_fn,pImg,NULL);
}
cvReleaseImage(&pImg);
cvReleaseCapture(&cap);
return frame;
}
//該函數借鑒了網上資料,自動創建多級目錄
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;
}
調用示例
//視頻轉圖片
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;
//圖片轉視頻
char* inputDir="E:\\woman_sequence\\Parameters_Good\\part_occ\\";
char* videoName="woman.avi";
char* outDir="E:\\VIDEOS\\TEST\\Videos\\";
int frames=ImageToVideo(outDir,videoName,inputDir,0,128,352,288,".jpg",30,1,CV_FOURCC('P','I','M','1'));
std::cout<<"total frames "<<frames<<" have been write to video."<<std::endl;
int p;
std::cin>>p;