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

时间:2011-12-12 10:34:00

标签: c# video emgucv

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

非常感谢你的帮助。

2 个答案:

答案 0 :(得分:13)

请在此处查看我的回答以供参考Emgu Capture plays video super fast

但是这应该按照你的要求我已经使用了一个列表存储你可以使用数组的图像,但你需要知道你的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();
    {
}

这是为了允许以负责任的速度播放视频文件,但是只需转换即可使用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
    }

}

您将不得不小心文件错误的结束,否则您将收到错误消息。您总是可以使用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

希望这有帮助,

干杯,

克里斯

答案 1 :(得分:0)

即使我面临同样的问题。所以我初始化了另一个计时器,并在那里提供了视频保存代码。只有当点击记录按钮[点击记录视频的表格上的按钮]时才启用此计时器。现在我可以捕捉视频,但音频没有被录制。