2012-06-29 3 views

ответ

17

Единственный практический способ сделать это - вручную извлечь кадры, закрепить их (в памяти или файлах), а затем перезагрузить их в обратном порядке.

Проблема заключается в том, что видеокомпрессоры используют время избыточности - тот факт, что два последовательных кадра в большинстве случаев очень похожи. Таким образом, они время от времени кодируют полный кадр (обычно каждые несколько сотен кадров), а затем посылают различия между предыдущим и текущим.

Теперь, для того, чтобы декодирование работало, оно должно выполняться в том же порядке - декодировать ключевой кадр (полный), а затем для каждого нового кадра добавлять различия для получения текущего изображения.

Эта стратегия очень затрудняет обратное воспроизведение видео. Существует несколько методов, но все они включают буферизацию.

Теперь вы, возможно, видели параметры CV_CAP_PROP_POS_FRAMES, описанные Astor. Это нормально, но из-за проблем, описанных выше, OpenCV не может правильно перейти к определенному фрейму (при этих проблемах открыто несколько ошибок). Они (разработчики OpenCV) работают над некоторыми решениями, но даже они будут очень медленными (они включают возврат к предыдущему ключевому кадру, а затем декодирование обратно к выбранному). Если вы используете эту технику, каждый кадр должен быть декодирован в сотни раз в среднем, делая его очень медленным. И все же это не сработает.

Редактировать Если вы преследуете путь буфера обратить его вспять, иметь в виду, что декодируют видео быстро объедать ресурсы памяти для обычного компьютера. Обычный 720p видео 1 минута4.7GB памяти при распаковке! Хранение кадров как отдельных файлов на диске является практическим решением этой проблемы.

+0

Хороший ответ +1. Не знал этого. Вы кодируете для OpenCV? – ArtemStorozhuk

+0

:) Не гей, хотя я думаю о некоторых исправлениях. Но у меня были некоторые проблемы с синхронизацией VideoCapture, и я обнаружил некоторые из ее недостатков. – Sam

+0

Хорошо, спасибо за вашу помощь – darasan

1

Да, это возможно. См. Код с комментариями:

//create videocapture 
VideoCapture cap("video.avi"); 

//seek to the end of file 
cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1); 

//count frames 
int number_of_frames = cap.get(CV_CAP_PROP_POS_FRAMES); 

//create Mat frame and window to display 
Mat frame; 
namedWindow("window"); 

//main loop 
while (number_of_frames > 0) 
{ 
    //decrease frames and move to needed frame in file 
    number_of_frames--; 
    cap.set(CV_CAP_PROP_POS_FRAMES, number_of_frames); 

    //grab frame and display it 
    cap >> frame; 
    imshow("window", frame); 

    //wait for displaying 
    if (waitKey(30) >= 0) 
    { 
     break; 
    } 
} 

Также прочитайте статью this.

+0

cap.set (CV_CAP_PROP_POS_FRAMES, number_of_frames); действительно забивает процессор, но работает. –

2

Другое решение, аналогично ArtemStorozhuk's answer является использование FPS для перемещения из области кадра во временную область, а затем искать в обратном направлении с помощью CV_CAP_PROP_POS_MSEC (который не забивает процессор, как CV_CAP_PROP_POS_FRAMES может). Вот мой пример кода, который отлично работает на .mpg, используя только около 50% CPU.

#include <opencv2/opencv.hpp> 

int main (int argc, char* argv[]) 
{ 
    cv::VideoCapture cap(argv[1]); 

    double frame_rate = cap.get(CV_CAP_PROP_FPS); 

    // Calculate number of msec per frame. 
    // (msec/sec/frames/sec = msec/frame) 
    double frame_msec = 1000/frame_rate; 

    // Seek to the end of the video. 
    cap.set(CV_CAP_PROP_POS_AVI_RATIO, 1); 

    // Get video length (because we're at the end). 
    double video_time = cap.get(CV_CAP_PROP_POS_MSEC); 

    cv::Mat frame; 
    cv::namedWindow("window"); 

    while (video_time > 0) 
    { 
    // Decrease video time by number of msec in one frame 
    // and seek to the new time. 
    video_time -= frame_msec; 
    cap.set(CV_CAP_PROP_POS_MSEC, video_time); 

    // Grab the frame and display it. 
    cap >> frame; 
    cv::imshow("window", frame); 

    // Necessary for opencv's event loop to work. 
    // Wait for the length of one frame before 
    // continuing the loop. Exit if the user presses 
    // any key. If you want the video to play faster 
    // or slower, adjust the parameter accordingly.  
    if (cv::waitKey(frame_msec) >= 0) 
     break; 
    } 
} 
+0

так .. поиск по msec меньше потребляет процессор, который ищет по кадру? Зачем? из-за сжатия? – nkint

+0

Я думаю, что это связано с тем, как кодируются видео ... в каждом пакете есть отметка времени, указывающая время с момента начала видео, поэтому поиск определенного времени в видео - это простая операция бинарного поиска. Но я не эксперт в области кодирования видео, поэтому сделайте этот комментарий с солью. –

Смежные вопросы