《OpenCV》Part4 OpenCV3.1.0 提取视频中的每一帧

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_24206709/article/details/53183465

《OpenCV》Part4 OpenCV3.1.0 提取视频中的每一帧

        看到一篇好的博文,忍不住扒下来了。提取视频中的每一帧,并保存成图片,支持摄像头和视频(.avi)中的图像抓取。

一、从摄像头获取初始化:

CvCapture* capture = cvCaptureFromCAM(0); // capture from video device #0
从视频文件filename.avi获取初始化:

CvCapture* capture = cvCaptureFromAVI("infile.avi");
抓取帧:
IplImage* img = 0; 
if(!cvGrabFrame(capture)){ // 抓取一帧,失败退出 
printf("Could not grab a frame\n");
exit(0);
}
img=cvRetrieveFrame(capture); // 恢复获取的帧图像
要从多个摄像头同时获取图像, 首先从每个摄像头抓取一帧. 在抓取动作都结束后再恢复帧图像.
释放抓取源(和释放单幅图像时类似):
cvReleaseCapture(&capture);
注意由设备抓取的图像是由capture函数自动分配和释放的. 不要试图自己释放它.
获取设备特性:
cvQueryFrame(capture); // this call is necessary to get correct 
// capture properties
int frameH = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
int frameW = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
int fps = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
int numFrames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);
所有帧数似乎只与视频文件有关. 用摄像头时不对,奇怪!!!.
获取帧信息:
float posMsec = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_MSEC);
int posFrames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES);
float posRatio = cvGetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO);
获取所抓取帧在视频序列中的位置, 从首帧开始按[毫秒]算. 或者从首帧开始从0标号, 获取所抓取帧的标号. 或者取相对位置,首帧为0,末帧为1, 只对视频文件有效。

设定所抓取的第一帧标号:
// 从视频文件相对位置0.9处开始抓取
cvSetCaptureProperty(capture, CV_CAP_PROP_POS_AVI_RATIO, (double)0.9);
只对从视频文件抓取有效. 不过似乎也不成功!!!

二、初始化视频存储器:

CvVideoWriter *writer = 0;
int isColor = 1;
int fps = 25; // or 30
int frameW = 640; // 744 for firewire cameras
int frameH = 480; // 480 for firewire cameras
writer=cvCreateVideoWriter("out.avi",CV_FOURCC('P','I','M','1'),
fps,cvSize(frameW,frameH),isColor);
其他有效编码:
CV_FOURCC('P','I','M','1') = MPEG-1 codec
CV_FOURCC('M','J','P','G') = motion-jpeg codec (does not work well)
CV_FOURCC('M', 'P', '4', '2') = MPEG-4.2 codec
CV_FOURCC('D', 'I', 'V', '3') = MPEG-4.3 codec
CV_FOURCC('D', 'I', 'V', 'X') = MPEG-4 codec
CV_FOURCC('U', '2', '6', '3') = H263 codec
CV_FOURCC('I', '2', '6', '3') = H263I codec
CV_FOURCC('F', 'L', 'V', '1') = FLV1 codec
若把视频编码设为-1则将打开一个编码选择窗口(windows系统下).
存储视频文件:
IplImage* img = 0; 
int nFrames = 50;
for(i=0;i<nFrames;i++){
cvGrabFrame(capture); // 抓取帧
img = cvRetrieveFrame(capture); // 恢复图像
cvWriteFrame(writer,img); // 将帧添加入视频文件
}
若想在抓取中查看抓取图像, 可在循环中加入下列代码:
cvShowImage("mainWin", img); 
key = cvWaitKey(20); // wait 20 ms
若没有20[毫秒]延迟,将无法正确显示视频序列.
释放视频存储器:
cvReleaseVideoWriter(&writer);

三、示例1:从视频中抓取每一帧,显示并保存

扫描二维码关注公众号,回复: 3362478 查看本文章
#include <cstring>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>

using namespace std;

int main(){
	CvCapture* capture;
	capture = cvCreateFileCapture("bike.avi");
	assert(capture!=NULL);

	IplImage *frame;
	cvNamedWindow("camera",1);

	int n = 1, m = 120;
	char* cstr = new char[120];

	while (m--)
	{
		frame = cvQueryFrame(capture);

		if (!frame)	   break;

		sprintf(cstr, "%s%d%s", "D:\\OpenCVWorkSpace\\video_capture\\video_capture",n++,".jpg");

		cvShowImage("camera",frame);

		cvSaveImage(cstr, frame);

		if (cvWaitKey(330)>=0)    break;

	}

	cvReleaseCapture(&capture);
	cvReleaseImage(&frame);
	cvDestroyWindow("camera");

	return 0;
}


四、示例2:从摄像头中提取图片后并将图片重新连续播放出来。

// 该程序实现视频和图片的相互转换.  
// Image_to_video()函数将一组图片合成AVI视频文件.  
// Video_to_image()函数将AVI视频文件读入,将每一帧存储为jpg文件.  
//  
////////////////////////////////////////////////////////////////////////  
#include <stdlib.h>  
#include <stdio.h>  
#include <math.h>  
#include <cv.h>  
#include <highgui.h>  
#define NUM_FRAME 300 //只处理前300帧,根据视频帧数可修改  

void Video_to_image(char* filename)
{
	printf("------------- video to image ... ----------------n");
	//初始化一个视频文件捕捉器  
	CvCapture* capture = cvCaptureFromAVI(filename);
	//获取视频信息  
	cvQueryFrame(capture);
	int frameH = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT);
	int frameW = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH);
	int fps = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FPS);
	int numFrames = (int)cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT);
	printf("tvideo height : %dntvideo width : %dntfps : %dntframe numbers : %dn", 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, ".jpg");//保存的图片名  

		cvSaveImage(image_name, img);   //保存一帧图片  

		if (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;
	int fps = 30; // or 25  
	int frameW = 400; // 744 for firewire cameras  
	int frameH = 240; // 480 for firewire cameras  
	writer = cvCreateVideoWriter("out.avi", CV_FOURCC('X', 'V', 'I', 'D'), fps, cvSize(frameW, frameH), isColor);
	printf("tvideo height : %dntvideo width : %dntfps : %dn", frameH, frameW, fps);
	//创建窗口  
	cvNamedWindow("mainWin", CV_WINDOW_AUTOSIZE);
	while (i < NUM_FRAME)
	{
		sprintf(image_name, "%s%d%s", "image", ++i, ".jpg");
		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[13] = "bike.avi";
	Video_to_image(filename); //视频转图片  
	Image_to_video();    //图片转视频  
	return 0;
}

五、示例3:从摄像头中提取图片,显示并保存。

由于本人不帅,所以这个程序就不贴效果图了,具体的效果自己贴到程序中测试,可以自我欣赏一下。

注意:

//////////////调用摄像头/////////////////

videoCapture cam;

cam.open(0);

/////////////设置摄像头窗口大小///////////////////

cam.set(CV_CAP_PROP_FRAM_WIDTH,600);

cam.set(CV_CAP_PROP_FRAM_HEIGHT,400);

/////////////获取摄像头视频中的每一帧///////////////////

cv::Mat cameraFrame;

camera>>cameraFrame;

//////////////存储从视频中获取的每一帧——存储路径与存储名称/////////////////

char* cstr = new char[120];
sprintf(cstr, "%s%d%s", "D:\\OpenCVWorkSpace\\video_capture\\video_capture",n++,".jpg");

///////////////openCV3.1.0中图片存储函数/////////////

imwrite(cstr,cameraFrame);//这个函数很重要,与cvSaveImage()这个函数不同,存储的图片类型是cv::Mat类型的,所以要注意

#include <cstring>  
#include <opencv2/opencv.hpp>  
#include <opencv2/highgui.hpp>  
#include <opencv2/video.hpp>  
#include "opencv2/imgproc/imgproc.hpp"    
#include "opencv2/ml/ml.hpp"   

using namespace std;
using namespace cv;

#include "opencv2/imgproc/imgproc.hpp"    
#include "opencv2/ml/ml.hpp"    

using namespace  std;
using namespace cv;

int main(int argc, char *argv[])
{
	int cameraNumber = 0;
	if (argc > 1)
		cameraNumber = atoi(argv[1]);
	VideoCapture  camera;
	camera.open(cameraNumber);

	camera.set(CV_CAP_PROP_FRAME_WIDTH, 600);//设置界面大小  
	camera.set(CV_CAP_PROP_FRAME_HEIGHT, 400);
	if (!camera.isOpened())
	{
		cerr << "ERROPR" << endl;
		exit(1);
	}

	int n = 1;
	while (true)
	{
		Mat  cameraFrame;
		camera >> cameraFrame;
		if (cameraFrame.empty())
		{
			cerr << "ERROR1" << endl;
			exit(1);
		}

 		char* cstr = new char[120];
 		sprintf(cstr, "%s%d%s", "D:\\OpenCVWorkSpace\\video_capture\\video_capture",n++,".jpg");

		imshow("Video", cameraFrame);
		
 		//const  CvArr* s = (CvArr*)&cameraFrame;
 		imwrite(cstr,cameraFrame);//这个函数很重要,与cvSaveImage()这个函数不同,存储的图片类型是cv::Mat类型的,所以要注意

		char key = cv::waitKey(50);
		if (key == 33)
		{
			break;
		}

	}
}

运行效果图略。


注意:在开启摄像头时,上面的程序不会出错,但是在调用视频的时候,视频结束时会有下述的错误:

OpenCV Error: Assertion failed (size.width>0 && size.height>0) in cv::imshow, file..\..\..\..\opencv\modules\highgui\src\window.cpp, line 261

这时就要注意,imread函数最好是放在if判断语句里面:

网上的说法:

我们用opencv打开视频的时候,会自动先监测摄像头有没有读到帧,如果没有,就会报错,然后再执行你的程序,加一个if判断就是跳过系统自己的判断,直接执行我们的程序。加上后确实可以解决错误。

			if (!img_src1.empty())
			{
				imshow("Froeground", img_src1);
			}
			else
			{
				return 0;
			}



猜你喜欢

转载自blog.csdn.net/sinat_24206709/article/details/53183465
今日推荐