OpenCV学习笔记(4)视频文件的读取与保存



那么,argc的值是 3,argv[0]是"video_test.exe",argv[1]是"v1.avi",argv[2]是"v2.mpg"。

OpenCV学习笔记(4)视频文件的读取与保存_第1张图片

(参见:http://www.opencv.org.cn/index.php/Main%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0argc%EF%BC%8Cargv%E8%AF%B4%E6%98%8E)

三、视频文件的读取与基本处理

这里主要是依照《Learning OpenCV》一书的例程修改实现的,其功能是读取2个视频文件,分别在两个窗口中播放,每个窗口都加入一个进度条,可以自行用鼠标控制播放进度。代码如下:

 

[cpp]  view plain copy
  1. // test2_video.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include   
  6. #include   
  7. //#include   
  8. #include   
  9. #include   
  10.   
  11. // 使用标准命名空间  
  12. using namespace std;  
  13.   
  14. // 初始化进度条的位置  
  15. int g_slider_position1 = 0;  
  16. int g_slider_position2 = 0;  
  17.   
  18. CvCapture* g_capture1 = NULL;  
  19. CvCapture* g_capture2 = NULL;  
  20.   
  21. // 定义回调函数用于播放进度的控制   
  22. void onTrackbarSlide1( int pos1 )  
  23. {  
  24.  cvSetCaptureProperty( g_capture1, CV_CAP_PROP_POS_FRAMES, pos1 );  
  25. }  
  26. void onTrackbarSlide2( int pos2 )  
  27. {  
  28.  cvSetCaptureProperty( g_capture2, CV_CAP_PROP_POS_FRAMES, pos2 );  
  29. }  
  30.   
  31.   
  32. int main(int argc, char** argv )  
  33. {  
  34.  // 建立播放窗口  
  35.  cvNamedWindow( "Video Test 1", CV_WINDOW_AUTOSIZE );  
  36.  cvNamedWindow( "Video Test 2", CV_WINDOW_AUTOSIZE );  
  37.   
  38.  // 捕捉视频文件  
  39.  g_capture1 = cvCreateFileCapture( argv[1] );  
  40.  g_capture2 = cvCreateFileCapture( argv[2] );  
  41.   
  42.  // 读取、显示视频文件的帧数  
  43.  int frames1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FRAME_COUNT );  
  44.  cout << "frames1 = " << frames1 << endl;  
  45.  // 建立进度条  
  46.  if( frames1 != 0 )  
  47.   cvCreateTrackbar(   
  48.    "Position",   
  49.    "Video Test 1",   
  50.    &g_slider_position1,   
  51.    frames1,   
  52.    onTrackbarSlide1  
  53.   );  
  54.   
  55.  int frames2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FRAME_COUNT );  
  56.  cout << "frames2 = " << frames2 << endl;  
  57.  if( frames2 != 0 )  
  58.   cvCreateTrackbar(   
  59.    "Position",   
  60.    "Video Test 2",   
  61.    &g_slider_position2,   
  62.    frames2,   
  63.    onTrackbarSlide2   
  64.   );  
  65.   
  66. // 读取视频文件信息  
  67.  double fps1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FPS );  
  68.  double fps2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FPS );  
  69.  CvSize size1 = cvSize(   
  70.   (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_WIDTH),  
  71.   (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_HEIGHT));  
  72.  CvSize size2 = cvSize(   
  73.   (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_WIDTH),  
  74.   (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_HEIGHT));  
  75.   
  76. // 创建 VideoWriter   
  77.  CvVideoWriter* wrVideo1 = cvCreateVideoWriter(argv[3], CV_FOURCC('M','J','P','G'), fps1, size1);  
  78.  CvVideoWriter* wrVideo2 = cvCreateVideoWriter(argv[4], CV_FOURCC('M','J','P','G'), fps2, size2);  
  79.   
  80.  int frs = 0;  
  81.   
  82.  // 开始播放并保存视频  
  83.  IplImage* frame1;  
  84.  IplImage* frame2;  
  85.    
  86.  while( frs < frames1 && frs < frames2 )  
  87.  {  
  88.   
  89.   // 获取、显示源文件的帧画面  
  90.   frame1 = cvQueryFrame( g_capture1 );  
  91.   if( !frame1 ) break;  
  92.   cvShowImage( "Video Test 1", frame1 );  
  93.   
  94.   frame2 = cvQueryFrame( g_capture2 );  
  95.   if( !frame2 ) break;  
  96.   cvShowImage( "Video Test 2", frame2 );  
  97.   
  98.   // 保存:将当前帧写入到目标视频文件  
  99.   
  100.   cvWriteFrame( wrVideo1, frame1 );  
  101.   cvWriteFrame( wrVideo2, frame2 );  
  102.     
  103.   // 若按下 ESC 键,则退出程序  
  104.   char c = cvWaitKey(33);  
  105.   if( c==27 ) break;  
  106.  }  
  107.  // 释放内存,关闭窗口  
  108.  cvReleaseCapture( &g_capture1 );  
  109.  cvReleaseCapture( &g_capture2 );  
  110.  cvReleaseVideoWriter( &wrVideo1 );  
  111.  cvReleaseVideoWriter( &wrVideo2 );  
  112.  cvDestroyWindow( "Video Test 1" );  
  113.  cvDestroyWindow( "Video Test 2" );  
  114.   
  115.  return 0;  
  116. }  

 

这里有几点需要注意的:

1、在菜单Project -> Properties -> Configuration Properties -> Linker –> Input 的 additional dependencies中加入 cxcore200.lib cv200.lib highgui200.lib opencv_ffmpeg200.lib 等库。opencv_ffmpeg200.lib 库可以支持多数主流视频文件格式(包括 rm、rmvb、flv 等)。

2、在这个程序中,进度条控制视频播放的功能貌似只对 AVI 文件有效,如果读入的是其它文件(例如MPG),则进度条失效。

3、关于 iostream 和 标准命名空间(namespace)

(1)和是不一样,在编译器include文件夹里面可以看到,二者是两个文件,里面的代码是不一样的。 后缀为.h的头文件c++标准已经明确提出不支持了,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 
因此,当使用时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;当使用的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。

(2)所谓namespace,是指标识符的各种可见范围。 c++标准程序库中的所有标识符都被定义于一个名为std的namespace中。 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:

—— 直接指定标识符。 

std::cout << std::hex << 3.4 << std::endl;

—— 使用using关键字。 

using std::cout; 
using std::endl;

以上程序可以写成 
cout << std::hex << 3.4 << endl;

—— 使用using namespace std。 
#include 
#include 
#include 
using namespace std;

这样命名空间std内定义的所有标识符都有效。就好像它们被声明为全局变量一样。那么以上语句可以如下写:

cout << hex << 3.4 << endl;

因为标准库非常的庞大,所程序员在选择的类的名称或函数名时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。 
但这又会带来了一个新问题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。所以就有了和等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。 命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加".h"。

(参见:http://www.kuqin.com/language/20080107/3532.html 和http://www.cnblogs.com/walkingmu/archive/2007/11/06/951400.html)

那么,argc的值是 3,argv[0]是"video_test.exe",argv[1]是"v1.avi",argv[2]是"v2.mpg"。

OpenCV学习笔记(4)视频文件的读取与保存_第2张图片

(参见:http://www.opencv.org.cn/index.php/Main%E5%87%BD%E6%95%B0%E5%8F%82%E6%95%B0argc%EF%BC%8Cargv%E8%AF%B4%E6%98%8E)

三、视频文件的读取与基本处理

这里主要是依照《Learning OpenCV》一书的例程修改实现的,其功能是读取2个视频文件,分别在两个窗口中播放,每个窗口都加入一个进度条,可以自行用鼠标控制播放进度。代码如下:

 

[cpp]  view plain copy
  1. // test2_video.cpp : Defines the entry point for the console application.  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include   
  6. #include   
  7. //#include   
  8. #include   
  9. #include   
  10.   
  11. // 使用标准命名空间  
  12. using namespace std;  
  13.   
  14. // 初始化进度条的位置  
  15. int g_slider_position1 = 0;  
  16. int g_slider_position2 = 0;  
  17.   
  18. CvCapture* g_capture1 = NULL;  
  19. CvCapture* g_capture2 = NULL;  
  20.   
  21. // 定义回调函数用于播放进度的控制   
  22. void onTrackbarSlide1( int pos1 )  
  23. {  
  24.  cvSetCaptureProperty( g_capture1, CV_CAP_PROP_POS_FRAMES, pos1 );  
  25. }  
  26. void onTrackbarSlide2( int pos2 )  
  27. {  
  28.  cvSetCaptureProperty( g_capture2, CV_CAP_PROP_POS_FRAMES, pos2 );  
  29. }  
  30.   
  31.   
  32. int main(int argc, char** argv )  
  33. {  
  34.  // 建立播放窗口  
  35.  cvNamedWindow( "Video Test 1", CV_WINDOW_AUTOSIZE );  
  36.  cvNamedWindow( "Video Test 2", CV_WINDOW_AUTOSIZE );  
  37.   
  38.  // 捕捉视频文件  
  39.  g_capture1 = cvCreateFileCapture( argv[1] );  
  40.  g_capture2 = cvCreateFileCapture( argv[2] );  
  41.   
  42.  // 读取、显示视频文件的帧数  
  43.  int frames1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FRAME_COUNT );  
  44.  cout << "frames1 = " << frames1 << endl;  
  45.  // 建立进度条  
  46.  if( frames1 != 0 )  
  47.   cvCreateTrackbar(   
  48.    "Position",   
  49.    "Video Test 1",   
  50.    &g_slider_position1,   
  51.    frames1,   
  52.    onTrackbarSlide1  
  53.   );  
  54.   
  55.  int frames2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FRAME_COUNT );  
  56.  cout << "frames2 = " << frames2 << endl;  
  57.  if( frames2 != 0 )  
  58.   cvCreateTrackbar(   
  59.    "Position",   
  60.    "Video Test 2",   
  61.    &g_slider_position2,   
  62.    frames2,   
  63.    onTrackbarSlide2   
  64.   );  
  65.   
  66. // 读取视频文件信息  
  67.  double fps1 = (int) cvGetCaptureProperty( g_capture1, CV_CAP_PROP_FPS );  
  68.  double fps2 = (int) cvGetCaptureProperty( g_capture2, CV_CAP_PROP_FPS );  
  69.  CvSize size1 = cvSize(   
  70.   (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_WIDTH),  
  71.   (int)cvGetCaptureProperty(g_capture1, CV_CAP_PROP_FRAME_HEIGHT));  
  72.  CvSize size2 = cvSize(   
  73.   (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_WIDTH),  
  74.   (int)cvGetCaptureProperty(g_capture2, CV_CAP_PROP_FRAME_HEIGHT));  
  75.   
  76. // 创建 VideoWriter   
  77.  CvVideoWriter* wrVideo1 = cvCreateVideoWriter(argv[3], CV_FOURCC('M','J','P','G'), fps1, size1);  
  78.  CvVideoWriter* wrVideo2 = cvCreateVideoWriter(argv[4], CV_FOURCC('M','J','P','G'), fps2, size2);  
  79.   
  80.  int frs = 0;  
  81.   
  82.  // 开始播放并保存视频  
  83.  IplImage* frame1;  
  84.  IplImage* frame2;  
  85.    
  86.  while( frs < frames1 && frs < frames2 )  
  87.  {  
  88.   
  89.   // 获取、显示源文件的帧画面  
  90.   frame1 = cvQueryFrame( g_capture1 );  
  91.   if( !frame1 ) break;  
  92.   cvShowImage( "Video Test 1", frame1 );  
  93.   
  94.   frame2 = cvQueryFrame( g_capture2 );  
  95.   if( !frame2 ) break;  
  96.   cvShowImage( "Video Test 2", frame2 );  
  97.   
  98.   // 保存:将当前帧写入到目标视频文件  
  99.   
  100.   cvWriteFrame( wrVideo1, frame1 );  
  101.   cvWriteFrame( wrVideo2, frame2 );  
  102.     
  103.   // 若按下 ESC 键,则退出程序  
  104.   char c = cvWaitKey(33);  
  105.   if( c==27 ) break;  
  106.  }  
  107.  // 释放内存,关闭窗口  
  108.  cvReleaseCapture( &g_capture1 );  
  109.  cvReleaseCapture( &g_capture2 );  
  110.  cvReleaseVideoWriter( &wrVideo1 );  
  111.  cvReleaseVideoWriter( &wrVideo2 );  
  112.  cvDestroyWindow( "Video Test 1" );  
  113.  cvDestroyWindow( "Video Test 2" );  
  114.   
  115.  return 0;  
  116. }  

 

这里有几点需要注意的:

1、在菜单Project -> Properties -> Configuration Properties -> Linker –> Input 的 additional dependencies中加入 cxcore200.lib cv200.lib highgui200.lib opencv_ffmpeg200.lib 等库。opencv_ffmpeg200.lib 库可以支持多数主流视频文件格式(包括 rm、rmvb、flv 等)。

2、在这个程序中,进度条控制视频播放的功能貌似只对 AVI 文件有效,如果读入的是其它文件(例如MPG),则进度条失效。

3、关于 iostream 和 标准命名空间(namespace)

(1)和是不一样,在编译器include文件夹里面可以看到,二者是两个文件,里面的代码是不一样的。 后缀为.h的头文件c++标准已经明确提出不支持了,c++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h。 
因此,当使用时,相当于在c中调用库函数,使用的是全局命名空间,也就是早期的c++实现;当使用的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。

(2)所谓namespace,是指标识符的各种可见范围。 c++标准程序库中的所有标识符都被定义于一个名为std的namespace中。 由于namespace的概念,使用C++标准程序库的任何标识符时,可以有三种选择:

—— 直接指定标识符。 

std::cout << std::hex << 3.4 << std::endl;

—— 使用using关键字。 

using std::cout; 
using std::endl;

以上程序可以写成 
cout << std::hex << 3.4 << endl;

—— 使用using namespace std。 
#include 
#include 
#include 
using namespace std;

这样命名空间std内定义的所有标识符都有效。就好像它们被声明为全局变量一样。那么以上语句可以如下写:

cout << hex << 3.4 << endl;

因为标准库非常的庞大,所程序员在选择的类的名称或函数名时就很有可能和标准库中的某个名字相同。所以为了避免这种情况所造成的名字冲突,就把标准库中的一切都被放在名字空间std中。 
但这又会带来了一个新问题。无数原有的C++代码都依赖于使用了多年的伪标准库中的功能,他们都是在全局空间下的。所以就有了和等等这样的头文件,一个是为了兼容以前的C++代码,一个是为了支持新的标准。 命名空间std封装的是标准程序库的名称,标准程序库为了和以前的头文件区别,一般不加".h"。

(参见:http://www.kuqin.com/language/20080107/3532.html 和http://www.cnblogs.com/walkingmu/archive/2007/11/06/951400.html)

你可能感兴趣的:(C++,OPENCV)