简体   繁体   English

在 C# 中将所有视频帧提取为图像的最快方法是什么?

[英]What is the fastest way to extract all frames of video into images in C#?

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:提取3分钟视频的帧花了整整2小时,原始视频是4分钟,但在视频快完成后它给了我一个内存错误:

'OpenCV: Failed to allocate 2764800 bytes' “OpenCV:无法分配 2764800 字节”

so, it takes a long time to complete the task and it has a few bugs I am using Emgu.CV and MediaToolkit所以,完成任务需要很长时间,并且有一些错误我正在使用 Emgu.CV 和 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.如果有人有解决方案可以加快速度并可能解决内存问题,我将不胜感激。

Here is an implementation using just Emgu.CV (I am not familiar with MediaToolKit ).这是仅使用Emgu.CV的实现(我不熟悉MediaToolKit )。

using (var video = new VideoCapture(file))
using (var img = new Mat())
{
    while (video.Grab())
    {
        video.Retrieve(img);
        var filename = Path.Combine(outputDirectory, $"{i}.png");
        CvInvoke.Imwrite(filename, img);
        i++;
    }
}

I tested this on a FullHD mp4 video.我在全高清mp4视频上对此进行了测试。 Don't know the exact codec.不知道确切的编解码器。 This takes roughly 65ms per frame with my CPU (i7-8700k).我的 CPU (i7-8700k) 每帧大约需要 65 毫秒。 But consider if you need to use the png format as it is slow to encode.但请考虑是否需要使用png格式,因为它的编码速度很慢。 If you don't want any compression loss and your harddisk is fast and big enough for bmp , it takes just 13ms per frame.如果您不想要任何压缩损失,并且您的硬盘对于bmp来说又快又大,那么每帧只需 13 毫秒。 jpg takes 40 ms. jpg需要 40 毫秒。

First of all, check for IDisposable objects without the "using".首先,检查没有“使用”的 IDisposable 对象。 For example, Bitmap inherits from Image, that implements IDisposable.例如,Bitmap 继承自 Image,它实现了 IDisposable。 So, when using the bimap, your code should be like this:所以,在使用 bimap 时,你的代码应该是这样的:

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.还要检查 Mat 类是否实现了 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.对于性能问题,我真的无能为力,但是 60fps 的 3 分钟视频是 10800 帧。 2 hours are 7200 seconds. 2 小时是 7200 秒。 So 0.6 seconds per frame.所以每帧 0.6 秒。 Is this really slow?这真的很慢吗? Just asking, I have no idea...只是问问,我不知道...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM