簡體   English   中英

在 C# 中將所有視頻幀提取為圖像的最快方法是什么?

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

我創建了一個應用程序來從視頻中提取每一幀。 它還不完美,並且有很多問題。 問題之一是需要多長時間。 提取3分鍾視頻的幀花了整整2小時,原始視頻是4分鍾,但在視頻快完成后它給了我一個內存錯誤:

“OpenCV:無法分配 2764800 字節”

所以,完成任務需要很長時間,並且有一些錯誤我正在使用 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();
        }
    }

如果有人有解決方案可以加快速度並可能解決內存問題,我將不勝感激。

這是僅使用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++;
    }
}

我在全高清mp4視頻上對此進行了測試。 不知道確切的編解碼器。 我的 CPU (i7-8700k) 每幀大約需要 65 毫秒。 但請考慮是否需要使用png格式,因為它的編碼速度很慢。 如果您不想要任何壓縮損失,並且您的硬盤對於bmp來說又快又大,那么每幀只需 13 毫秒。 jpg需要 40 毫秒。

首先,檢查沒有“使用”的 IDisposable 對象。 例如,Bitmap 繼承自 Image,它實現了 IDisposable。 所以,在使用 bimap 時,你的代碼應該是這樣的:

using (Bitmap bitmap = _video.QueryFrame().ToBitmap())
{
    bitmap.Save(String.Format(@"C:\\frames\\videoframe-{0}.png", i), ImageFormat.Png);
}

還要檢查 Mat 類是否實現了 IDisposable。 如果是這種情況,另一種使用可以幫助您解決內存問題。

對於性能問題,我真的無能為力,但是 60fps 的 3 分鍾視頻是 10800 幀。 2 小時是 7200 秒。 所以每幀 0.6 秒。 這真的很慢嗎? 只是問問,我不知道...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM