C# 用C语言将所有视频帧提取成图像的最快方法是什么?

C# 用C语言将所有视频帧提取成图像的最快方法是什么?,c#,emgucv,C#,Emgucv,我创建了一个从视频中提取每一帧的应用程序。它还不完美,有很多问题。问题之一是需要多长时间。提取3分钟视频的帧花了整整2个小时,原始视频是4分钟,但在视频几乎完成后,它给了我一个内存错误: “OpenCV:分配2764800字节失败” 因此,完成任务需要很长时间,并且有一些bug 我正在使用Emgu.CV和MediaToolkit 这是我的密码: using Emgu.CV; using MediaToolkit; using MediaToolkit.Model; st

我创建了一个从视频中提取每一帧的应用程序。它还不完美,有很多问题。问题之一是需要多长时间。提取3分钟视频的帧花了整整2个小时,原始视频是4分钟,但在视频几乎完成后,它给了我一个内存错误:

“OpenCV:分配2764800字节失败”

因此,完成任务需要很长时间,并且有一些bug 我正在使用Emgu.CV和MediaToolkit

这是我的密码:

  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();
        }
    }

如果有人能找到一个更快的解决方案,并可能解决内存问题,我将不胜感激。

首先,在不使用内存的情况下检查IDisposable对象。例如,位图继承自实现IDisposable的Image。因此,在使用bimap时,您的代码应如下所示:

using (Bitmap bitmap = _video.QueryFrame().ToBitmap())
{
    bitmap.Save(String.Format(@"C:\\frames\\videoframe-{0}.png", i), ImageFormat.Png);
}
还要检查Mat类是否实现了IDisposable。如果是这样的话,另一次使用可以帮助您解决内存问题


对于性能问题,我真的无能为力,但是3分钟的视频,每秒60帧,是10800帧。2小时等于7200秒。所以每帧0.6秒。这真的很慢吗?只是问一下,我不知道…

首先,在不使用IDisposable的情况下检查IDisposable对象。例如,位图继承自实现IDisposable的Image。因此,在使用bimap时,您的代码应如下所示:

using (Bitmap bitmap = _video.QueryFrame().ToBitmap())
{
    bitmap.Save(String.Format(@"C:\\frames\\videoframe-{0}.png", i), ImageFormat.Png);
}
还要检查Mat类是否实现了IDisposable。如果是这样的话,另一次使用可以帮助您解决内存问题


对于性能问题,我真的无能为力,但是3分钟的视频,每秒60帧,是10800帧。2小时等于7200秒。所以每帧0.6秒。这真的很慢吗?只是问一下,我不知道…

这里有一个使用Emgu.CV的实现,我不熟悉MediaToolKit


我在全高清mp4视频上测试了这个。我不知道确切的编解码器。使用我的CPU i7-8700k,每帧大约需要65毫秒。但是如果你需要使用PNG格式,因为编码速度很慢。如果你不想有任何压缩损失,而且你的硬盘速度快,可以容纳bmp,那么每帧只需13毫秒。jpg需要40毫秒。

这里是一个仅使用Emgu.CV的实现,我不熟悉MediaToolKit


我在全高清mp4视频上测试了这个。我不知道确切的编解码器。使用我的CPU i7-8700k,每帧大约需要65毫秒。但是如果你需要使用PNG格式,因为编码速度很慢。如果你不想有任何压缩损失,而且你的硬盘速度快,可以容纳bmp,那么每帧只需13毫秒。jpg需要40毫秒。

您从未处理过您_video.QueryFrame.ToBitmap的位图-这是内存泄漏无法分配2764800字节-猜测您的视频是960x720?我真的不知道,但您似乎有两次调用_video.QueryFrame.ToBitmap,也许可以重用返回的位图?另外,我猜行preview.Image=\u video.QueryFrame.ToBitmap;更新GUI?这可能很慢。根据这个文档,QueryFrame返回一个Mat对象,它似乎有Save。。。方法,调用该方法可能比首先将其转换为分配内存的位图更快?然后保存位图。在PictureBox的文档中有一个示例,它在显示新图像之前先处理图像。我的直觉告诉我,运行程序的两个小时中有相当一部分时间是用来更新预览的。试着在没有预览的情况下运行程序,看看它是否会产生影响。您可以运行第一个x帧并测量有/没有预览所需的时间您从不处理您的_video.QueryFrame.ToBitmap的位图-这是您的内存泄漏无法分配2764800字节-猜您的视频是960x720?我真的不知道,但您似乎有两个调用_video.QueryFrame.ToBitmap,也许可以重用返回的位图?另外,我猜行preview.Image=\u video.QueryFrame.ToBitmap;更新GUI?这可能很慢。根据这个文档,QueryFrame返回一个Mat对象,它似乎有Save。。。方法,调用该方法可能比首先将其转换为分配内存的位图更快?然后保存位图。在PictureBox的文档中有一个示例,它在显示新图像之前先处理图像。我的直觉告诉我,运行程序的两个小时中有相当一部分时间是用来更新预览的。试着在没有预览的情况下运行程序,看看它是否会产生影响。您可以运行第一个x帧并测量带/不带预览所需的时间。因此,最好使用已经测试过的工具作为FFMpeg。请看其他问题:另外,使用已经测试过的工具作为FFMpeg可能更好。见本节,其他问题: