前一阵子,实验室老师个了个小命题,就是如何提取一段AVI视频中的图片,或者说视频帧的提取。虽然是第一次接触OPENCV,可是做起来也是不难的,自己的代码就不拿出来了,写的很乱,网上的这个代码比较不错,为了说明我们的主题,姑且拿这段代码做个试验。
#include <stdlib.h> #include <stdio.h> #include <math.h> #include <cv.h> #include <highgui.h> #define NUM_FRAME 5591 //只处理前300帧,根据视频帧数可修改 int frameH; int frameW; int fps; int numFrames; void Video_to_image(char* filename) { printf("------------- video to image ... ----------------\n"); //初始化一个视频文件捕捉器 CvCapture* capture = cvCaptureFromAVI(filename); //获取视频信息 cvQueryFrame(capture); frameH = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT); frameW = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH); fps = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS); numFrames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); printf("\tvideo height : %d\n\tvideo width : %d\n\tfps : %d\n\tframe numbers : %d\n", frameH, frameW, fps, numFrames); //定义和初始化变量 int i = 0; IplImage* img = 0; char image_name[13]; cvNamedWindow( "mainWin", CV_WINDOW_AUTOSIZE ); //读取和显示 while(1) { img = cvQueryFrame(capture); //获取一帧图片 cvShowImage( "mainWin", img ); //将其显示 char key = cvWaitKey(20); sprintf(image_name, "%s%d%s", "image", ++i, ".bmp");//保存的图片名 cvSaveImage( image_name, img); //保存一帧图片 if(i >=numFrames || i >= NUM_FRAME ) break; } cvReleaseCapture(&capture); cvDestroyWindow("mainWin"); } void Image_to_video() { int i = 0; IplImage* img = 0; char image_name[13]; printf("------------- image to video ... ----------------\n"); //初始化视频编写器,参数根据实际视频文件修改 CvVideoWriter *writer = 0; int isColor = 1; writer=cvCreateVideoWriter("out.avi",CV_FOURCC('X','V','I','D'),fps,cvSize(frameW,frameH),isColor); printf("\tvideo height : %d\n\tvideo width : %d\n\tfps : %d\n", frameH, frameW, fps); //创建窗口 cvNamedWindow( "mainWin", CV_WINDOW_AUTOSIZE ); while(i<NUM_FRAME) { sprintf(image_name, "%s%d%s", "image", ++i, ".bmp"); img = cvLoadImage(image_name); if(!img) { printf("Could not load image file...\n"); exit(0); } cvShowImage("mainWin", img); char key = cvWaitKey(20); cvWriteFrame(writer, img); } cvReleaseVideoWriter(&writer); cvDestroyWindow("mainWin"); } int main(int argc, char *argv[]) { char filename[23] = "F:\\1_Xvid.avi"; Video_to_image(filename); //视频转图片 Image_to_video(); //图片转视频 return 0; }
配置好OPENCV环境(WIN7 + VS2010)之后,这段代码是可以运行的,可是,实验室师兄师姐们的主流实用VC6开发的,所以老师让我把代码在VC6下调试出来。
结果配置好VC6之后,一运行出现这个错误:Null pointer in function cvGetMat
首先找资料是怎么回事,有的人说是内存不足之类的原因,建议在循环体里面释放窗体资源,我照做了,可是还是不行。
郁闷了老半天,还是没有结果。。。。。
后来我发现一个细节,就是说,视频的信息压根就没有读进来,可以看看控制台。
找到原因之后,后来就相对好办了,其实也花了很长时间去做。
网上很多人说是解码器的问题,建议安装K-Lite_Codec_Pack_3.9.5Full,我也试了,在实验室蛋疼的网速之下,苦苦等待,安装,结果不知道为什么还是不行,。
最后阶段,一个偶然的机会,我看到这篇文章 http://hqs2892805.blog.163.com/blog/static/379968312010722915630/
结果按照这篇文章这么做,就实现了。。。
如果AVI文件打不开,请下载VIRTUALDUB图像处理软件,然后把AVI文件用XVID编码,编码后的文件不会太大。我自己用摄像头拍摄的AVI有5兆,编码后只有不到2兆,而且能够用VC打开。
http://www.xvidmovies.com/codec/ 可以从这个网站下载xvid解编码器
方法:file——open video file
video——compression——选择XVIDMPEG CODEC
哈哈,庆祝一下