2012-06-29 19 views
10

¿Es posible reproducir videos al revés en OpenCV? Ya sea mediante una llamada API o mediante el almacenamiento en búfer de marcos de video y la inversión de la orden en un nuevo archivo de video.Reproducción de video inverso en OpenCV

Gracias

Respuesta

17

La única forma práctica de hacerlo es extraer manualmente los marcos, almacenarlos en búfer (en la memoria o archivos) y luego volver a cargarlos en orden inverso.

El problema es que los compresores de video están explotando la redundancia de tiempo, el hecho de que dos cuadros consecutivos son la mayoría de las veces muy similares. Por lo tanto, codifican un fotograma completo de vez en cuando (generalmente cada pocos cientos de fotogramas) y luego solo envían diferencias entre el anterior y el actual.

Ahora, para que la decodificación funcione, debe hacerse en el mismo orden: decodifique un fotograma clave (uno completo), luego, para cada fotograma nuevo, agregue las diferencias para obtener la imagen actual.

Esta estrategia hace que sea muy difícil invertir la reproducción en video. Hay varias técnicas, pero todas implican el almacenamiento en búfer.

Ahora, es posible que haya visto los parámetros CV_CAP_PROP_POS_FRAMES, descritos por Astor. Parece correcto, pero debido a los problemas descritos anteriormente, OpenCV no puede saltar correctamente a un marco específico (hay varios errores abiertos en estos temas). Ellos (desarrolladores de OpenCV) están trabajando en algunas soluciones, pero incluso esas serán muy lentas (implican volver al fotograma clave anterior y luego decodificar de nuevo al seleccionado). Si utiliza esta técnica, cada cuadro debe decodificarse cientos de veces en promedio, lo que lo hace muy lento. Y, sin embargo, no funciona.

Editar Si persigues el camino búfer de revertirla, tenga en cuenta que un vídeo decodificado va a comer rápidamente de los recursos de memoria de un ordenador normal. Un video habitual de 720p de un minuto necesita 4.7GB de memoria cuando se descomprime! El almacenamiento de marcos como archivos individuales en el disco es una solución práctica para este problema.

+0

Buena respuesta +1. No lo sabía ¿Codifica para OpenCV? – ArtemStorozhuk

+0

:) no es así, aunque estoy pensando en algunos parches. Pero he tenido algunos problemas con la sincronización de VideoCapture, y descubrí algunos de sus defectos. – Sam

+0

OK, gracias por su ayuda – darasan

1

Sí, es posible. Ver código con comentarios:

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

Lea también this artículo.

+0

cap.set (CV_CAP_PROP_POS_FRAMES, number_of_frames); realmente martilla la CPU, pero funciona. –

2

Otra solución, similar a ArtemStorozhuk's answer es utilizar el FPS para moverse desde el dominio de marco en el dominio del tiempo, a continuación, Buscar hacia atrás usando CV_CAP_PROP_POS_MSEC (que no martillo la CPU como CV_CAP_PROP_POS_FRAMES puede). Aquí está mi código de muestra, que funciona perfectamente en un .mpg, usando solo alrededor del 50% de 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

tan .. buscando por msec es menos consumo de CPU que buscar por marco? ¿por qué? debido a la compresión? – nkint

+0

Creo que tiene que ver con la forma en que se codifican los videos ... hay una marca de tiempo en cada paquete, que indica el tiempo desde el inicio del video, por lo que buscar un momento particular dentro del video es una simple operación de búsqueda binaria. Pero no soy un experto en codificaciones de video, así que tome este comentario con un grano de sal. –

Cuestiones relacionadas