macos 如何使用 OpenCV 编写视频文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4872383/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to write a video file with OpenCV?
提问by CCS
I am trying to write a program to analyze emotional expressions like tears. As part of my tracker I am using OpenCV to record sample videos. Particularly, I am not certain about how to correctly choose FPS (10FPS seems like it ought to work). I am also not sure which Codec I should use on OS X, I have tried all possible CV_FOURCC from hereas well but returned the following error:
我正在尝试编写一个程序来分析眼泪等情绪表达。作为我的跟踪器的一部分,我使用 OpenCV 来录制示例视频。特别是,我不确定如何正确选择 FPS(10FPS 似乎应该可行)。我也不确定我应该在 OS X 上使用哪个编解码器,我也从这里尝试了所有可能的 CV_FOURCC但返回了以下错误:
Stream #0.0: Video: rawvideo, yuv420p, 640x480, q=2-31, 19660 kb/s, 90k tbn, 10 tbc
Assertion failed: (image->imageSize == avpicture_get_size( (PixelFormat)input_pix_fmt, image->width, image->height )), function writeFrame, file /opt/local/var/macports/build/_opt_local_var_macports_sources_rsync.macports.org_release_ports_graphics_opencv/work/OpenCV-2.2.0/modules/highgui/src/cap_ffmpeg.cpp, line 1085.
Do you all have some working code with cvWriteFrame? Thanks for taking time to look at my problem!
你们都有一些使用 cvWriteFrame 的工作代码吗?感谢您抽出时间来查看我的问题!
For those interested the entire program is:
对于那些有兴趣的人,整个程序是:
#include <cv.h>
#include <cxcore.h>
#include <highgui.h>
int main (int argc, const char * argv[])
{
CvCapture *capture;
IplImage *img;
int key = 0;
CvVideoWriter *writer;
// initialize camera
capture = cvCaptureFromCAM( 0 );
// capture = cvCaptureFromAVI("AVIFile");
// always check
assert( capture );
// create a window
cvNamedWindow( "video", 1 );
int color = 1; // 0 for black and white
// get the frame size
CvSize size = cvSize((int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH),(int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT));
writer = cvCreateVideoWriter(argv[1], -1 , 10 , size, color);
while( key != 'q' ) {
// get a frame
img = cvQueryFrame( capture );
// always check
if( !img ) break;
cvWriteFrame( writer, img );
cvShowImage("video", img );
// quit if user press 'q'
key = cvWaitKey( 5 );
}
// free memory
cvReleaseVideoWriter( &writer );
cvReleaseCapture( &capture );
cvDestroyWindow( "video" );
return 0;
}
回答by mpenkov
Have a look herefor the recommended codecs to use.
看看这里推荐的编解码器使用。
Basically:
基本上:
- You can use
-1
instead ofCV_FOURCC(...)
only if you're on Windows(see the manual). Since you're on OSX, you can't use it. - Use
CV_FOURCC('I', 'Y', 'U', 'V')
to encode using yuv420p into an uncompressed AVI container -- this is the recommended approach - If you want compressed video, then you can use tools like
ffmpeg
to compress the AVI output by OpenCV
- 您可以使用
-1
而不是CV_FOURCC(...)
仅当您在 Windows 上使用时(请参阅手册)。由于您使用的是 OSX,因此无法使用它。 - 用于
CV_FOURCC('I', 'Y', 'U', 'V')
使用 yuv420p 编码到未压缩的 AVI 容器中——这是推荐的方法 - 如果你想要压缩视频,那么你可以使用像
ffmpeg
OpenCV 压缩 AVI 输出的工具
The reason OpenCV doesn't recommend using compressor codecs is probably because each codec has a large number of codec-specific options, and dealing with all of them through the simple OpenCV video writer interface would be impossible.
OpenCV 不推荐使用压缩编解码器的原因可能是因为每个编解码器都有大量特定于编解码器的选项,并且通过简单的 OpenCV 视频编写器界面处理所有这些选项是不可能的。
EDIT
编辑
I have some bad news:
我有一些坏消息:
Unfortunately, we still have no working (i.e. native) video writer for Mac OS X. If you need video writing, you should currently configure for ffmpeg or xine and disable QuickTime.
不幸的是,我们仍然没有适用于 Mac OS X 的可用(即本机)视频编写器。如果您需要编写视频,您当前应该配置 ffmpeg 或 xine 并禁用 QuickTime。
Sounds like you may need to reconfigure and recompile your library.
听起来您可能需要重新配置和重新编译您的库。
EDIT 2
编辑 2
Alternatively, you could just write each frame to a JPEG file, and then stitch those JPEG files into a movie using ffmpeg
(that should work on OS/X). This is essentially what MJPEG is, anyway. You'll probably get better compression rates with codecs that exploit temporal redundancy (e.g. MPEG4, H.264, etc), though.
或者,您可以将每一帧写入一个 JPEG 文件,然后使用ffmpeg
(应该在 OS/X 上工作)将这些 JPEG 文件拼接成电影。无论如何,这基本上就是 MJPEG。不过,使用利用时间冗余的编解码器(例如 MPEG4、H.264 等),您可能会获得更好的压缩率。
回答by cooplogic
The assertion suggests that there is a size mismatch between the image being sent to the video writer, and the size specified when initializing the video writer. I would suggest adding some debug statements as follows:
该断言表明发送到视频编写器的图像与初始化视频编写器时指定的大小之间存在大小不匹配。我建议添加一些调试语句如下:
cout << "Video Size: " << size.width << "," << size.height << endl;
cout << "Image Size: " << img.cols << "," << img.rows << endl;
That should help you find out if the sizes are different.
这应该可以帮助您确定尺寸是否不同。
With regard to the fourcc question, it looks like you are using cap_ffmpeg instead of cap_qtkit. You may want to try recompiling with ffmpeg off, since the qtkit version of capture works pretty well on OS X. Rather than using macports, you can directly download opencv2.2 from sourceforge and use ccmake to configure opencv not to use ffmpeg, in that case qtkit will be the default.
关于fourcc 问题,看起来您正在使用cap_ffmpeg 而不是cap_qtkit。您可能想尝试关闭 ffmpeg 重新编译,因为 qtkit 版本的捕获在 OS X 上运行良好。您可以直接从 sourceforge 下载 opencv2.2 并使用 ccmake 将 opencv 配置为不使用 ffmpeg,而不是使用 macports case qtkit 将是默认值。
If you do use qtkit, then you need to use the fourcc('j','p','e','g');
如果你使用qtkit,那么你需要使用fourcc('j','p','e','g');
The frame rate should match the frame rate of the input. You can use the properties to get the frame rate similar to the way you got the frame width and height, however since you are capturing from the camera, you will probably have to test the capture rate by using a timer in your code and estimating from that.
帧速率应与输入的帧速率相匹配。您可以使用这些属性来获取帧速率,类似于获取帧宽度和高度的方式,但是由于您是从相机捕获的,因此您可能必须通过在代码中使用计时器并估计来测试捕获速率那。
Here is an example based on starter_video.cpp that will work with qtkit:
下面是一个基于 starter_video.cpp 的例子,它适用于 qtkit:
/*
* starter_video_write.cpp
*
* Created on: Nov 23, 2010
* Author: Ethan Rublee
* Modified on: Aug 3, 2011 by David Cooper
*
* A starter sample for using opencv, get a video stream and display the images
* easy as CV_PI right?
* edited to add writing capability for OS X using qtkit.
*/
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <vector>
#include <stdio.h>
using namespace cv;
using namespace std;
//hide the local functions in an anon namespace
namespace {
void help(char** av) {
cout << "\nThis program justs gets you started reading images from video\n"
"Usage:\n./" << av[0] << " <video device number>\n"
<< "q,Q,esc -- quit\n"
<< "space -- save frame\n\n"
<< "\tThis is a starter sample, to get you up and going in a copy pasta fashion\n"
<< "\tThe program captures frames from a camera connected to your computer.\n"
<< "\tTo find the video device number, try ls /dev/video* \n"
<< "\tYou may also pass a video file, like my_vide.avi instead of a device number"
<< endl;
}
int process(VideoCapture& capture) {
int n = 0;
char filename[200];
string window_name = "video | q or esc to quit";
cout << "press space to save a picture. q or esc to quit" << endl;
namedWindow(window_name, CV_WINDOW_KEEPRATIO); //resizable window;
Mat frame;
double frameRate = 15.0;
capture >> frame;
VideoWriter* writer = NULL;
// FIXME: need to change this to an absolute path that exists on this system
string outputFile = "/tmp/test.mov";
writer = new VideoWriter(outputFile,
CV_FOURCC('j','p','e','g'),
frameRate,Size(frame.cols,frame.rows));
for (;;) {
capture >> frame;
if (frame.empty())
continue;
imshow(window_name, frame);
writer->write(frame);
char key = (char)waitKey(5); //delay N millis, usually long enough to display and capture input
switch (key) {
case 'q':
case 'Q':
case 27: //escape key
if(writer != NULL) {
delete writer;
}
return 0;
case ' ': //Save an image
sprintf(filename,"filename%.3d.jpg",n++);
imwrite(filename,frame);
cout << "Saved " << filename << endl;
break;
default:
break;
}
}
return 0;
}
}
int main(int ac, char** av) {
if (ac != 2) {
help(av);
return 1;
}
std::string arg = av[1];
VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file
if (!capture.isOpened()) //if this fails, try to open as a video camera, through the use of an integer param
capture.open(atoi(arg.c_str()));
if (!capture.isOpened()) {
cerr << "Failed to open a video device or video file!\n" << endl;
help(av);
return 1;
}
return process(capture);
}
回答by net_programmer
I had the same problem. I solved it by using the Planar RGB Codec.
我有同样的问题。我通过使用平面 RGB 编解码器解决了它。
outputVideo.open(PathName, CV_FOURCC('8','B','P','S'), myvideo.get(CV_CAP_PROP_FPS),CvSize(outputframe.size()));
The output size is important, but it works without installing anything.
输出大小很重要,但它无需安装任何东西即可工作。
回答by user2218016
After reading misha's answer. I resolved this problem under Mac OS 10.9 Mavericks and XCode 5 by reinstall opencv using Homebrew.
阅读 misha 的回答后。我通过使用 Homebrew 重新安装 opencv 在 Mac OS 10.9 Mavericks 和 XCode 5 下解决了这个问题。
brew install opencv --with-ffmpeg
brew install opencv --with-ffmpeg
回答by speciousfool
I think the CV_FOURCC
line may be incorrect. A similar questionsuggests using -1
as a CV_FOURCC
test value to prompt you with the working choices on your system.
我认为这CV_FOURCC
条线可能不正确。一个类似的问题建议使用-1
作为CV_FOURCC
测试值来提示您系统上的工作选择。
Can you try to compile the program from that question and tell us if using a value of -1
instead of V_FOURCC('M', 'J', 'P', 'G')
writes an AVI file?
您能否尝试从该问题编译程序并告诉我们是否使用值-1
而不是V_FOURCC('M', 'J', 'P', 'G')
写入 AVI 文件?
回答by Francisco Calderon
I think that's because of the size of the video - try others, more common like 640X480
or 320X240
.
我认为这是因为视频的大小 - 尝试其他人,更常见的是640X480
或320X240
。
It works for me.
这个对我有用。