OpenCV+C++ 视频图片相互转换

OpenCV+C++ 视频图片相互转换

在平时的实验中,经常需要将视频保存为一帧一帧的图片,以获取实验结果;另一方面,很多标准的算法测试数据库都是图片序列(文件名以帧号+图片扩展名),我们可能需要将其转换为视频,因此视频与图片之间的转换是很常见的操作;以下分享一下自己平时编写和使用的两段很简单但是实用的代码;

(由于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;