Emgu CV从视频文件中获取所有帧

本文关键字:获取 文件 CV 视频 Emgu | 更新日期: 2023-09-27 18:17:28

我想请您帮助我使用Emgu CV从视频文件中获取所有帧。我知道我可以使用Capture类和它的QueryFrame()方法,但是这只返回一个帧。获得所有的帧最简单的方法是什么?(并保存它,例如Image<Bgr, Byte>[])我需要所有帧做一些更多的处理(更具体地说:关键帧提取视频摘要)。

非常感谢你的帮助

Emgu CV从视频文件中获取所有帧

参考我的回答Emgu Capture播放视频超快

但是这应该可以满足你的要求,我已经使用列表来存储图像,你可以使用数组,但你需要知道你的avi文件有多大。

Timer My_Time = new Timer();
int FPS = 30;
List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>();
Capture _capture;    
public Form1()
{
    InitializeComponent();
    //Frame Rate
    My_Timer.Interval = 1000 / FPS;
    My_Timer.Tick += new EventHandler(My_Timer_Tick);
    My_Timer.Start()
    _capture = new Capture("test.avi");   
}
private void My_Timer_Tick(object sender, EventArgs e)
{
    Image<Bgr, Byte> frame = _capture.QueryFrame();
    if (frame != null)
    {
        imageBox.Image = _capture.QueryFrame();
        image_array.Add(_capture.QueryFrame().Copy());
    }
    else
    {
         My_Timer.Stop();
    {
}

这是为了允许以负责任的速率播放视频文件,但作为您的简单转换,您可以使用应用程序。空闲方法就像这样简单…

List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>();
Capture _capture;
    
public Form1()
{
    InitializeComponent();
    //Frame Rate
    _capture = new Capture("test.avi");   
    Application.Idle += ProcessFrame;
}
private void ProcessFrame(object sender, EventArgs arg)
{
    Image<Bgr, Byte> frame = _capture.QueryFrame();
    if (frame != null)
    {
        image_array.Add(frame.Copy());
    }
    else
    {
        Application.Idle -= ProcessFrame;// treat as end of file
    }
    
}

你要小心文件的最后出错你会收到一个错误。您总是可以使用try catch语句来捕获它将给出的特定错误,而不是简单地终止转换。

如果你使用图像数组,你将不得不循环遍历文件,增加变量并计算帧数,然后在将视频文件转换为数组之前创建图像数组。


[编辑]

根据要求,这是一个从视频文件中检索所有帧的方法版本。我没有在大型视频文件上进行测试,因为我预计程序会崩溃,因为它将需要大量内存。

    private List<Image<Bgr, Byte>> GetVideoFrames(String Filename)
    {
        List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>();
        Capture _capture = new Capture(Filename);
        bool Reading = true;
        while (Reading)
        {
            Image<Bgr, Byte> frame = _capture.QueryFrame();
            if (frame != null)
            {
                image_array.Add(frame.Copy());
            }
            else
            {
                Reading = false;
            }
        }
        return image_array;
    }

或者我意识到你可能希望从网络摄像头记录10秒的视频,所以这个方法可以做到这一点,我使用秒表作为while循环禁止使用计时器,除非你的多线程应用程序

    private List<Image<Bgr, Byte>> GetVideoFrames(int Time_millisecounds)
    {
        List<Image<Bgr,Byte>> image_array = new List<Image<Bgr,Byte>>();
        System.Diagnostics.Stopwatch SW = new System.Diagnostics.Stopwatch();
        
        bool Reading = true;
        Capture _capture = new Capture();
        SW.Start();
        while (Reading)
        {
            Image<Bgr, Byte> frame = _capture.QueryFrame();
            if (frame != null)
            {
                image_array.Add(frame.Copy());
                if (SW.ElapsedMilliseconds >= Time_millisecounds) Reading = false;
            }
            else
            {
                Reading = false;
            }
        }
        return image_array;
    }

,它可以这样调用:

List<Image<Bgr, Byte>> Image_Array = GetVideoFrames(10000); //10 Secounds

希望有帮助,

欢呼,克里斯

我也面临同样的问题。所以我初始化了另一个计时器,并在其中提供了视频保存代码。这个计时器只有在点击录制按钮(表单上用于点击录制视频的按钮)时才会启用。现在我可以捕获视频,但音频没有被记录。