C# 为什么使用 OpenCV VideoCapture 时我的视频帧速率较慢?

问题描述 投票:0回答:2

我正在尝试从文件中读取视频(.mp4)并将其显示在表单上的图像框上。当我计算它的总播放时间时,它实际上比实际视频长度要长。例如,如果视频实际长度为 10 秒,则播放时间为 12-13 秒。这是为什么?我的视频帧率为 31fps

我尝试确保 fps 变量已经具有正确的帧速率。

private void Play_Video(string filePath)
{
    VideoCapture cameraCapture = new VideoCapture(filePath);

    var stopwatch = new Stopwatch();
    stopwatch.Start();
    while (true)
    {
        Mat m = new Mat();
        cameraCapture.Read(m);
        if (!m.IsEmpty)
        {
            imageBox1.Image = m;
            double fps = cameraCapture.GetCaptureProperty(CapProp.Fps);
            Thread.Sleep(1000 / Convert.ToInt32(fps));
        }
        else
        {
            break;
        }
    }
    stopwatch.Stop();
    double elapsed_time = stopwatch.ElapsedMilliseconds * 0.001;
    // My elapsed_time here shows about 13 seconds, when the actual length of video is 10 seconds. Why?
}

新编辑: 我在单独的函数中更新了帧检索,以免在渲染过程中造成延迟,但仍然有几秒钟的延迟。例如,30 秒的视频会播放 32-33 秒。我更新的代码:

private void Play_Video(List<Mat> frames, double fps, Emgu.CV.UI.ImageBox imageBox)
{
    var stopwatch = new Stopwatch();
    stopwatch.Start();

    for (int i = 0; i < frames.Count; i++)
    {
        imageBox.Image = frames[i];
        Thread.Sleep(1000 / Convert.ToInt32(fps));
    }
    stopwatch.Stop();
    double elapsed_time = stopwatch.ElapsedMilliseconds * 0.001;
}
c# opencv video-streaming video-capture emgucv
2个回答
0
投票

这是我获得准确 fps 的唯一方法,因为使用 thread.sleep 需要 10-15 毫秒来循环打开和关闭。我对 Task.Delay 也有同样的问题。这似乎工作得很好,如果有人有更好的解决方案,我很乐意看到它。

    private void PlayVideo()
    {
        double framecount = video.Get(Emgu.CV.CvEnum.CapProp.FrameCount);
        double fps = video.Get(Emgu.CV.CvEnum.CapProp.Fps);

        video.Set(Emgu.CV.CvEnum.CapProp.PosFrames, (double)(framecount * (double)(savePercent / 100)));
        int ms = Convert.ToInt32(((double)1000 / fps));

        while (disablePreviewTimer == false)
        {
            DateTime dt = DateTime.Now;
            Emgu.CV.Mat img = video.QueryFrame();
            if (img == null)
            {
                disablePreviewTimer = true;
                break;
            }
            else
            {
                Emgu.CV.Util.VectorOfByte vb = new Emgu.CV.Util.VectorOfByte();
                Emgu.CV.CvInvoke.Resize(img, img, PreviewSize);
                Emgu.CV.CvInvoke.Imencode(".jpg", img, vb);

                pictureBox5.Image = Image.FromStream(new MemoryStream(vb.ToArray()));
                Application.DoEvents();

                while ((DateTime.Now - dt).TotalMilliseconds < ms)
                {
                    Application.DoEvents();
                }

                label6.Text = ((int)(DateTime.Now - dt).TotalMilliseconds).ToString();
            }
        }
    }

0
投票

有点晚了,但对于其他遇到此问题的人来说,请使用秒表。

private Stopwatch _sw = new();
private long _fpsInterval = 1000/fps;
private long _currentInterval = 0;

//skipping all the setup but you will want to ensure you start your stopwatch.

private void SomeMethod()
{
while(true)
{
    if (_sw.ElapsedMilliseconds > _currentInterval)
    {
    //do all your CV stuff here
    _currentInterval += _fpsInterval
    }
}

我显然把剩下的留给你,但我努力解决这个确切的问题,并让我所有的东西的时间完全正确,这似乎是确保你在每个间隔内获得一个帧的最佳方法。

© www.soinside.com 2019 - 2024. All rights reserved.