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

tom*_*tom 8 c# video emgucv

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

非常感谢你的帮助.

Chr*_*ris 14

请参阅我的答案以供参考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();
    {
}
Run Code Online (Sandbox Code Playgroud)

这是为了允许以负责任的速度播放视频文件,但是只需转换即可使用Application.Idle方法,就像这样容易...

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
    }

}
Run Code Online (Sandbox Code Playgroud)

您将不得不小心文件错误的结束,您将收到错误.您始终可以使用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;
    }
Run Code Online (Sandbox Code Playgroud)

或者我意识到你可能希望从网络摄像头录制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;
    }
Run Code Online (Sandbox Code Playgroud)

这将被称为这样:

List<Image<Bgr, Byte>> Image_Array = GetVideoFrames(10000); //10 Secounds
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助,

干杯,

克里斯