Подтвердить что ты не робот

Воспроизведение обратного видео в OpenCV

Можно ли воспроизводить видео назад в OpenCV? Либо вызовом API, либо буферизацией видеокадров, и отменой порядка в новый видеофайл.

Спасибо

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

Другим решением, аналогичным АртемStorozhuk ответить, является использование FPS для перехода из области фрейма во временную область, а затем искать назад с помощью CV_CAP_PROP_POS_MSEC (что doesn 't забивать процессор, как 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 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;
  }
}

Ответ 3

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

//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;
    }
}

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