Size in kbytes of AVI of video in C++/OpenCV - c++

Is there a way to know the size of an avi video in OpenCV? There are some videos that are blank and instead of processing them I want to get rid of them by comparing their size to a threshold. For example, if the size of the video is 200 kB or less, then I skip processing that video.
Update:
CvCapture *capture = cvCreateFileCapture(path);
IplImage *img = cvQueryFrame( capture );
All videos have the same number of frames but some videos have all blank frames.

You can get number of frames by getting CV_CAP_PROP_FRAME_COUNT video property using GetCaptureProperty:
CV_CAP_PROP_FRAME_COUNT Number of frames in the video file.
To get size of file (video) there is another API - depends on your system (WinAPI, POSIX etc).
For example on Windows it's GetFileSizeEx() function.
Also look at this SO discussion.

If you want to get the actual file size, you will have to use fopen() or stat as OpenCV doesn't store this information in a cvCapture object. However, you can detect blank videos like so:
CvCapture *capture = cvCaptureFromAVI( argv[1] );
int numFrames = (int) cvGetCaptureProperty(&capture, CV_CAP_PROP_FRAME_COUNT);
Then just decide if it's blank based on the number of frames.
Relevant Documentation:
http://opencv.willowgarage.com/documentation/reading_and_writing_images_and_video.html?highlight=cvcapture#getcaptureproperty
If the file size is different for the blank videos, but the files have the same number of frames, it's due to video compression via keyframing. That means the best way to detect blank frames is via getting the file size, which is outside of the scope of OpenCV and can easily be accomplished using plain C/C++:
#include <sys/stat.h>
...
struct stat st;
stat(avi_filename, &st);
size = st.st_size;

Related

How do we skip frame, calculate number of frames and get current frame with video reader

I am using Opencv for video decoding now. I can play the video with no problem. However, I could not find a way to skip frame, get total number of frames and current frame number. Is there a way to use VideoReader like VideoCapture? I have gone through their api and could not get anything.
OpenCV is Open Source library. If you use VideoCapture then the object of this class has any methods:
To skip a frame you should read 2 times a frame.
To get total number of frames as follows:
cv::VideoCapture m_capture;
....
int totalFrames = m_capture.get(cv::CAP_PROP_FRAME_COUNT)
To get a current frame number:
int currentFrame = m_capture.get(cv::CAP_PROP_POS_FRAMES)
For detailed information visit the OpenCV documentation https://docs.opencv.org/3.1.0/d8/dfe/classcv_1_1VideoCapture.html.

OpenCV (C++): write produces big file compared to input

I am trying to read a video file using OpenCV (C++), apply a filter to each frame and write a new modified frame into an output file.
The crucial parts of the code are these:
int out_format = CV_FOURCC('M','P','4','2'); // can be another one
double fps = media.get(CV_CAP_PROP_FPS),
width = media.get(CV_CAP_PROP_FRAME_WIDTH),
height = media.get(CV_CAP_PROP_FRAME_HEIGHT);
// On Linux FFMPEG is used to write videos
VideoWriter writer("./" + outputname + ".mkv", out_format, fps, Size(width, height) );
.......
.......
writer.write(newFrame); // Mat newFrame
The fact is, I am not proficient with codecs and video output formats, thus I would like to know why a file which is around 280 MB produces an output of 2 GB.
Is that a codec problem? I have tried DIVX, MPEG and others. Moreover, some output formats must go together with specific codecs.
Try using the 'M','P', '4', 'V' codec with the .mp4 container, that is, set the extension to your filename as something.mp4
For the mp4 container, you could also try, MPEG, MJPG, FMP4

OpenCV: Memory leak when writing video from webcam using cvWriteFrame

I want to record video from webcam using opencv.
I put the following code inside a timer event handler function, which is called each 50 ms
IplImage *image = cvQueryFrame(camera);
IplImage *resizeImage = cvCreateImage( size, 8, 3);
cvResize(image, resizeImage);
cvWriteFrame(writer, resizeImage );
With writer is created using cvCreateVideoWriter, and the video is created when I call cvReleaseVideoWriter(&writer)
The problem is I can not release memory allocated by cvWriteFrame until cvReleaseVideoWriter is called. That makes a big issue when I need record a long time video.
How can I handle this situation?
I suppose that the best solution in your case (if you don't want to modify OpenCV code), is to write several video files.
As I can suppose, each frame is grabbed to RAM as is without any compressing. So, you can calculate a number of frames before amount of allocated memory exceed a particular size. Then you finish writing to file and start a new one.

Writing variable framerate videos in openCV

The steps I follow for writing a video file in openCV are as follows:
CvVideoWriter *writer =cvCreateVideoWriter(fileName, Codec ID, frameRate, frameSize); // Create Video Writer
cvWriteFrame(writer, frame); // Write frame
cvReleaseVideoWriter(&writer); // Release video writer
The above code snippet writes at a fixed frame rate. I need to write out variable frame rate videos. The approach I had used earlier with libx264 involved writing individual timestamps to each frame.
So, the question is how do I write timestamps to a frame in openCV - what is the specific API ? More generally, how do I create variable frame rate videos ?
I don't think it is possible to do this with OpenCV directly without modifying the code to give access under the hood. You would need to use a different library like libvlc to do so using the imem to get your raw RGB frames in OpenCV into a file. This link provides an example using imem with raw images loaded from OpenCV. You would just need to change the :sout options to save to the file you want using your preferred codec.

loadRawData Memory issue in ogre while load opencv frames

I am capturing images in real time using OpenCV, and I want to show these images in the OGRE window as a background. So, for each frame the background will change.
I am trying to use MemoryDataStream along with loadRawData to load the images into an OGRE window, but I am getting the following error:
OGRE EXCEPTION(2:InvalidParametersException): Stream size does not
match calculated image size in Image::loadRawData at
../../../../../OgreMain/src/OgreImage.cpp (line 283)
An image comes from OpenCV with a size of 640x480 and frame->buffer is a type of Mat in OpenCV 2.3. Also, the pixel format that I used in OpenCV is CV_8UC3 (i.e., each pixel is 8-bits and each pixel contains 3 channels ( B8G8R8 ) ).
Ogre::MemoryDataStream* videoStream = new Ogre::MemoryDataStream((void*)frame->buffer.data, 640*480*3, true);
Ogre::DataStreamPtr ptr(videoStream,Ogre::SPFM_DELETE);
ptr->seek(0);
Ogre::Image* image = new Ogre::Image();
image->loadRawData(ptr,640, 480,Ogre::PF_B8G8R8 );
texture->unload();
texture->loadImage(*image)
Why I always getting this memory error?
Quick idea, maybe memory 4-byte alignment issues ?
see Link 1 and
Link 2
I'm not an Ogre expert, but does it work if you use loadDynamicImage instead?
EDIT : Just for grins try using the Mat fields to setup the buffer:
Ogre::Image* image = new Ogre::Image();
image->loadDynamicImage((uchar*)frame->buffer.data, frame->buffer.cols, frame->buffer.rows, frame->buffer.channels(), Ogre::PF_B8G8R8);
This will avoid copying the image data, and should let the Mat delete it's contents later.
I had similar problems to get image data into OGRE, in my case the data came from ROS (see ros.org). The thing is that your data in frame->buffer is not RAW, but has a file header etc.
I think my solution was to search the data stream for the beginning of the image (by finding the appropriate indicator in the data block, e.g. 0x4D 0x00), and inserting the data from this point on.
You would have to find out were in your buffer the header ends and where your data begins.