Emgu CV получить все кадры из видеофайла

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

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


person tom    schedule 12.12.2011    source источник


Ответы (2)


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

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


[ИЗМЕНИТЬ]

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

    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

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

Ваше здоровье,

Крис

person Chris    schedule 12.12.2011
comment
Спасибо, я просто не хочу использовать его в Application.Idle. Я просто хочу иметь функцию, которую я могу вызывать, когда захочу, и она возвращает мне список кадров Image‹Bgr,Byte› из данного видеовхода. - person tom; 07.01.2012
comment
Привет, я добавил код в метод, который вы могли бы вызвать, я надеюсь, что это то, что вам нужно, если нет, дайте мне знать. - person Chris; 09.01.2012
comment
@Chris, вы можете мне помочь stackoverflow .com/questions/31259051/ - person gihansalith; 07.07.2015

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

person Ahammed    schedule 10.11.2012