常见的视频跟踪数据库,如:
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’)等,可能会与某视频后缀名不匹配,造成视频编解码问题,无法读取。