Эмгу CV получить все кадры из видео файла - PullRequest
8 голосов
/ 12 декабря 2011

Я хотел бы попросить вас помочь мне получить все кадры из видеофайла с помощью Emgu CV. Я знаю, что могу использовать класс Capture и его метод QueryFrame(), но он возвращает только один кадр. Какой самый простой способ получить все кадры? (и сохраните его, например, в Image<Bgr, Byte>[]). Мне нужно, чтобы все кадры были обработаны (точнее: извлечение ключевых кадров для суммирования видео).

Большое спасибо за вашу помощь.

Ответы [ 2 ]

14 голосов
/ 12 декабря 2011

См. Мой ответ здесь для справки 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();
    {
}

Это было разработано, чтобы позволить воспроизведение видеофайла с ответственной скоростью, но в качестве простого преобразования вы можете использовать метод 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, чтобы перехватить конкретную ошибку, которую он выдаст, вместо того, чтобы просто прекратить преобразование.

Если вы используете массив изображений, вам придется перебирать файл, увеличивая переменную и считая кадры, а затем создавать массив изображений перед преобразованием видеофайла в массив.


[EDIT]

Как и требовалось, это методическая версия извлечения всех кадров из видеофайла. Я не проверял это на большом видеофайле, так как ожидаю, что программа будет аварийно завершена, поскольку она потребует много памяти.

    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

Надеюсь, это поможет,

Приветствия

Chris

0 голосов
/ 10 ноября 2012

Даже я столкнулся с той же проблемой. Так что я инициализировал другой таймер и предоставил туда код сохранения видео. И этот таймер включается только при нажатии кнопки записи [Кнопка в форме, которая при записи записывает видео].Теперь я могу снимать видео, но звук не записывается.

...