c++ and openCV with windows8: VideoWriter class not opening - c++

I am trying to record a video using openCV's class VideoWriter.
Using the following function,
void addFrameToVideo(Mat& frame)
{
if(_vid.open("test.avi", CV_FOURCC('M','J','P','G'), 30, frame.size(), 1))
cout << "here" << endl;
_vid.write(frame);
}
_vid is a variable of type VideoWriter and I can imshow frame with no problems.
The if condition never verifies, since the program never outputs "here".
However, this code actually creates a "test.avi" file in the directory, but it remains empty.
I've tried several different compression methods with no success.
Any thoughts?

It is possible that the codec could not be found in your system. You should try using different codecs. Alternatively, you can pass the value -1 instead of CV_FOURCC() and a window will pop up at runtime that contains all the codec installed on your system and ask you to select the one to use (this only works on Windows).

Related

OpenCV, can't release CAP_OPENCV_MJPEG VideoWriter for long records

Hi stackoverflow community,
I recently had a problem with the performance of the opencv VideoWriter (see here), and I am now using cv::CAP_OPENCV_MJPEG as a backend instead of cv::CAP_FFMPEG.
Now I am running in another issue, so my code looks like this:
cv::VideoWriter videoWriter(path, cv::CAP_OPENCV_MJPEG, fourcc, fps, *size);
videoWriter.set(cv::VIDEOWRITER_PROP_QUALITY, 100);
int id = metaDataWriter.insertNow(path);
while (this->isRunning) {
while (!this->stackFrames.empty()) {
cv:Mat m = this->stackFrames.pop();
videoWriter << m;
}
}
videoWriter.release();
This loop runs in a separate thread and "isRunning" will be switched from outside. There is a stack with cv::Mat (stackFrames) which is filled by another thread that captures the images by a video capture card. This works fine, but if the file size is too big, several GB, I get the following error when the videoWriter.release() is called:
terminate called after throwing an instance of 'cv::Exception'
what(): OpenCV(4.4.0) /home/michael-gary/opencv/opencv/modules/videoio/src/container_avi.cpp:27: error: (-211:One of the arguments' values is out of range) Failed to write AVI file: chunk size is out of bounds in function 'safe_int_cast'
I tried to change the video container from .avi to .mkv, .mp4, .mpg but none of them is working, it does not even create the file. Only .avi is working, but fails by the release.
For now I will try to write multiple files, so I don't run in this problem, but I would like to face the problem itself.
Open for any suggestions
BR Michael
AVI files are practically limited in size.
when you force it to use OPENCV_MJPEG, it will only use OpenCV's own writing methods, which can only do AVI and MJPEG.
if you need a different container, you have to use a different backend, such as FFMPEG. you can still have MJPG for a codec (fourcc).

PlaySound() function won't play sound

First question, sorry if I don't do something right :S. I'm attempting to loop a background audio track while a game created in the console window is played. This is part of a group project. The game runs fine but I simply can't get the audio track to play using the PlaySound() function. This is a test program I made to try to figure out the problem.
#include <iostream>
#include <windows.h>
#include <mmsystem.h>
using namespace std;
int main()
{
PlaySound(TEXT("D:\\CodeBlocks:\\Programming Work:\\SoundTest:\\castor.wav"), NULL, SND_FILENAME|SND_ASYNC|SND_LOOP);
if(PlaySound(TEXT("D:\\CodeBlocks:\\Programming Work:\\SoundTest:\\castor.wav"), NULL, SND_FILENAME|SND_ASYNC|SND_LOOP))
{
cout << "It's Working." << endl;
}
else
{
cout << "It's not working." << endl;
}
cout << "Hello world!" << endl;
return 0;
}
My test case returns true (or "It's working."), and when I tried it in the school computer lab, it would loop the default windows error tone, which plays when the function can't find the file you specified, even though I've given it the whole file path. I can't figure out why it can't find the file, I've quadruple checked that it is in fact located where I wrote the file path, and it still seems unable to find it. I've tried using both .mp3 and .wav formats for the audio file. Anyone know what's going on?
(note: The linker needs to be given the winmm library for this)
Thanks guys, I found the actual problem, it wasn't even code all along. Turns out my audio file (castor.wav) was not actually in wav format, which is required by the PlaySound() function, even though the computer was telling me it was .wav (Even when I showed the properties of the file, it said it was in wav format).
This is because I attempted to convert it from a .mp3 by simply changing .mp3 to .wav, should have known better. After using an actual conversion program (and removing the exact file path and simply giving it TEXT("castor.wav") it works like a charm. Thanks for the help!

OpenCV VideoCapture: Howto get specific frame correctly?

I am trying to get at specific frame from a video file using OpenCV 2.4.11.
I have tried to follow the documentation and online tutorials of how to do it correctly and have now tested two approaches:
1) The first method is brute force reading each frame using the video.grab() until I reach the specific frame (timestamp) I want. This method is slow if the specific frame is late in the video sequence!
string videoFile(videoFilename);
VideoCapture video(videoFile);
double videoTimestamp = video.get(CV_CAP_PROP_POS_MSEC);
int videoFrameNumber = static_cast<int>(video.get(CV_CAP_PROP_POS_FRAMES));
while (videoTimestamp < targetTimestamp)
{
videoTimestamp = video.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = static_cast<int>(video.get(CV_CAP_PROP_POS_FRAMES));
// Grabe frame (but don't decode the frame as we are only "Fast forwarding")
video.grab();
}
// Get and save frame
if (video.retrieve(frame))
{
char txtBuffer[100];
sprintf(txtBuffer, "Video1Frame_Target_%f_TS_%f_FN_%d.png", targetTimestamp, videoTimestamp, videoFrameNumber);
string imgName = txtBuffer;
imwrite(imgName, frame);
}
2) The second method I uses the video.set(...). This method is faster and doesn't seem to be any slower if the specific frame is late in the video sequence.
string videoFile(videoFilename);
VideoCapture video2(videoFile);
videoTimestamp = video2.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = static_cast<int>(video2.get(CV_CAP_PROP_POS_FRAMES));
video2.set(CV_CAP_PROP_POS_MSEC, targetTimestamp);
while (videoTimestamp < targetTimestamp)
{
videoTimestamp = video2.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = (int)video2.get(CV_CAP_PROP_POS_FRAMES);
// Grabe frame (but don't decode the frame as we are only "Fast forwarding")
video2.grab();
}
// Get and save frame
if (video2.retrieve(frame))
{
char txtBuffer[100];
sprintf(txtBuffer, "Video2Frame_Target_%f_TS_%f_FN_%d.png", targetTimestamp, videoTimestamp, videoFrameNumber);
string imgName = txtBuffer;
imwrite(imgName, frame);
}
Problem) Now the issue is that using the two methods does end up with the same frame number of the content of the target image frame is not equal?!?
I am tempted to conclude that Method 1 is the correct one and there is something wrong with the OpenCV video.set(...) method. But if I use the VLC player finding the approximate target frame position it is actually Method 2 that is closest to a "correct" result?
As some extra info: I have tested the same video sequence but in two different video files being encoded with respectively 'avc1' MPG4 and 'wmv3' WMV codec.
Using the WMV file the two found frames are way off?
Using the MPG4 file the two found frames are only slightly off?
Is there anybody having some experience with this, can explain my findings and tell me the correct way to get a specific frame from a video file?
Obviously there's still a bug in opencv/ ffmpeg.
ffmpeg doesn't deliver the frames that are wanted and/or opencv doesn't handles this. See here and here.
[Edit:
Until that bug is fixed (either in ffmpeg or (as a work-around in opencv)) the only way to get exact frame by number is to "fast forward" as you did.
(Concerning VLC-player: I suspect that it uses that buggy set ()-interface. As for a player it is usually not too important to seek frame-exact. But for an editor it is).]
I think that OpenCV uses FFmpeg for video decoding.
We once had a similar problem but used FFmpeg directly. By default, random (but exact) frame access isn't guaranteed. The WMV decoder was particularly fuzzy.
Newer versions of FFmpeg allow you access to lower-level routines which can be used to build a retrieval function for frames. This solution was a little involved and nothing I can remember off my head right now. I try to find some more details later.
As a quick work-around, I would suggest to decode your videos off-line and then work on sequences off images. Though, this increases the amount of storage needed, it guarantees exact random frame access. You can use FFmpeg to convert your video file in to a sequence of images like this:
ffmpeg -i "input.mov" -an -f image2 "output_%05d.png"

OpenCV displaying avi file encoded in I420

I am trying to write a video processing application using OpenCV 2.4.2 (in Visual C++ 2010 Express on Windows 7) but I am having trouble displaying certain AVI files. Most display correctly, but when I use an AVI file encoded in I420 format all I get is a striped pink image for every frame (it displays correctly in regular media players).
Output displayed: http://i.imgur.com/BOu6c.png?1
Currently, I am using the C++ API, but the same thing happens when I use the C API (code from this page: http://nashruddin.com/how_to_play_avi_files_with_opencv). I find this strange, because in most answers on this site and resources on the web, they explicitly recommend to use the I420 encoding. Does anyone know what could be causing this or how to fix it?
Here is a trimmed down version of the code I am using:
int main(int argc, char** argv){
string fname = "test.avi";
VideoCapture capture(fname);
if(!capture.isOpened()){
cerr << "error opening " << fname << endl;
return -1;
}
Mat frame;
namedWindow("output");
double rate = capture.get(CV_CAP_PROP_FPS);
int delay = 1000/rate;
while(true){
if(!capture.read(frame)) break;
cv::imshow("output", frame);
if(waitKey(delay) >= 0) break;
}
capture.release();
return 0;
}
I am using is the pre-compiled version of OpenCV if that makes a difference (http://sourceforge.net/projects/opencvlibrary/).
Ok, so I managed to test on a few more computers. One just crashed and, on another, the video played fine. It turns out that it was a problem with FFMPEG being enabled in the default OpenCV compilation having problems with the uncompressed AVI. Recompile OpenCV with FFMPEG disabled or just use a different codec to compress the video.

Problem with iterating over a lots of images in OpenCv with mac os

I'm trying to iterator over some directories containing approximately 3000 images. I load the image. If the image is loaded I release it.
That is the smallest program that I can write to reproduce the error.
After loading and releasing 124 images the program stops loading images. I think this a memory issue but I don't understand what exactly causes the program to stop loading images.
I'm using OpenCV on my Mac. I don't know how exactly I can figure out which version I'm using.
Here is the Code from my project.
bool FaceDetectionStrategy::detectFace(std::string imagePath) {
IplImage *img = cvLoadImage(imagePath.c_str(), CV_LOAD_IMAGE_COLOR);
if (img) {
std::cout << "Image loaded " << imagePath << std::endl;
cvReleaseImage(&img);
} else {
std::cout << "Image not loaded " << imagePath << std::endl;
}
return true;
}
This method is called for every image in the directorys I'm iterating through. After 124 images the if(img) part evaluates to false and the else branch is executed. If I try to load images from other parts of the program later on they also won't load.
Edit it is not a memory issue. Mac Os standard max open files is 256 after changing it to 512 I can open 251 images. so it seems that OpenCV doesn't closes the image files after loading them.
Searching the bugtracker from OpenCv showed this answer to the problem: cvLoadImage with Mac ImageIO leaves file handles open.
It seems that this is a bug in the OpenCV mac implementation and the only way to solve it is to install a newer version of OpenCV.
EDIT installing the last version of OpenCV from the repository trunk solves the problem. Sometimes it helps checking the BugTracker of the frameworks you are using...
Behavior concerning memory rarely has to do with a consistent number, in my experience. The only way it could be that consistent is if there is some sort of internal limit in cvLoadImage that happens to be the not-very-common number 124. But your logic seems fine to me, that your images should be released.
More likely, since I assume your directories aren't changing between tests, that 125th image is bad.
Have you verified that the image you are trying to load actually exists? If it does (which it probably does), check that the image file format is supported by OpenCV. If that is also true, make sure the file is not corrupted by opening it with another editor.
You can have OpenCV help you out with errors. Use cvGetErrStatus() to check if there was an error, then use cvErrorStr() to get a textual description of it. You can do something like this:
// I would recommend putting this in a file, like CVUtility.h
#include <exception>
void check_CV_Error(void)
{
int errorCode = cvGetErrStatus();
if (errorCode) // I'm assuming 0 means no reportable error
{
throw std::runtime_error(cvErrorStr(errorCode));
// std::cerr << cvErrorStr(errorCode);
// ^ if you would rather not use exceptions
}
}
Your code then becomes:
bool FaceDetectionStrategy::detectFace(std::string imagePath) {
IplImage *img = cvLoadImage(imagePath.c_str(), CV_LOAD_IMAGE_COLOR);
if (img) {
std::cout << "Image loaded " << imagePath << std::endl;
cvReleaseImage(&img);
} else {
std::cout << "Image not loaded " << imagePath << std::endl;
check_CV_Error(); // find reason for error
}
return true;
And that will throw an exception for you to catch and log, and possibly react on. (Or print the error to console if you use the std::cerr version)