I have created a application to extract every frame from a video. It is not perfect yet and has a lot of problems with it. One of the problems is how long it takes. It took a full 2 hours to extract the frames of a 3 minutes video and the original video was four minutes but it gave me a memory error after the video was nearly finished:
'OpenCV: Failed to allocate 2764800 bytes'
so, it takes a long time to complete the task and it has a few bugs I am using Emgu.CV and MediaToolkit
Here is my code:
using Emgu.CV;
using MediaToolkit;
using MediaToolkit.Model;
string file;
private void CreateFrames()
{
int i = 0;
VideoCapture _video = new VideoCapture(file);
var videoInfo = new MediaFile { Filename = file };
using (var engine = new Engine()) { engine.GetMetadata(videoInfo); }
while (i <= videoInfo.Metadata.Duration.Milliseconds * videoInfo.Metadata.VideoData.Fps)
{
Mat m = new Mat();
_video.Read(m);
_video.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.PosFrames, i);
preview.Image = _video.QueryFrame().ToBitmap();
Bitmap bitmap = _video.QueryFrame().ToBitmap();
bitmap.Save(String.Format(@"C:\\frames\\videoframe-{0}.png", i),
ImageFormat.Png);
i++;
}
}
private async void browse_Click(object sender, EventArgs e)
{
DialogResult result = openFileDialog.ShowDialog();
if (result == DialogResult.OK)
{
file = openFileDialog.FileName;
var videoInfo = new MediaFile { Filename = file };
using (var engine = new Engine()) { engine.GetMetadata(videoInfo); }
label1.Text = videoInfo.Metadata.VideoData.Fps + " \n" +
videoInfo.Metadata.Duration.ToString();
// must be run on a second thread else it will not work and it will freeze
Task getframes = new Task(CreateFrames);
getframes.Start();
}
}
I would appreciate if somebody has a solution to make this faster and possibly a fix to the memory problem.
First of all, check for IDisposable objects without the "using". For example, Bitmap inherits from Image, that implements IDisposable. So, when using the bimap, your code should be like this:
using (Bitmap bitmap = _video.QueryFrame().ToBitmap())
{
bitmap.Save(String.Format(@"C:\\frames\\videoframe-{0}.png", i), ImageFormat.Png);
}
Also check if the Mat class implements IDisposable. If it is the case, another using could help you with the memory problem.
For the performance issue, I really cant help, but 3 minutes video, at 60fps, are 10800 frames. 2 hours are 7200 seconds. So 0.6 seconds per frame. Is this really slow? Just asking, I have no idea...