Lecture vidéo inversée dans OpenCV

est-il possible de lire des vidéos à l'envers dans OpenCV? Soit par un appel API, soit en tamponnant les images vidéo et en inversant la commande en un nouveau fichier vidéo.

Merci

12
demandé sur darasan 2012-06-29 14:20:37

3 réponses

la seule façon pratique de le faire est d'extraire manuellement les cadres, de les buffer ( sur la mémoire ou les fichiers) puis de les recharger dans l'ordre inverse.

le problème est que les compresseurs vidéo exploitent tous la redondance temporelle - le fait que deux images consécutives sont la plupart du temps très similaires. Ainsi, ils encodent une image complète de temps en temps (généralement toutes les quelques centaines d'images) puis n'envoient que des différences entre le précédent et le courant.

maintenant, pour que le décodage fonctionne, il doit être fait dans le même ordre - décodage d'une image clé (plein), puis pour chaque nouvelle image, ajouter des différences pour obtenir l'image en cours.

cette stratégie rend très difficile la lecture inversée en vidéo. Il y a plusieurs techniques, mais toutes impliquent la mise en tampon.

Maintenant, vous avez peut-être vu les paramètres CV_CAP_PROP_POS_FRAMES, décrits par Astor. Il semble ok, mais en raison des problèmes décrits ci-dessus, OpenCV n'est pas en mesure de sauter correctement à un cadre spécifique (il ya plusieurs bogues ouverts sur ces questions). Ils (OpenCV devs) travaillent sur quelques solutions, mais même celles-ci seront très lentes (elles impliquent de revenir à l'image clé précédente, puis de décoder à nouveau l'image choisie). Si vous utilisez cette technique, chaque image doit être décodé des centaines de fois en moyenne, il est très lent. Et pourtant, il ne fonctionne pas.

Modifier Si vous suivez la méthode buffer Pour l'Inverser, gardez à l'esprit qu'une vidéo décodée va rapidement dévorer les ressources de mémoire d'un ordinateur ordinaire. Une vidéo habituelle de 720p une minute besoins 4.7 GO de mémoire en cas de décompression! Stocker des cadres sous forme de fichiers individuels sur disque est une solution pratique à ce problème.

18
répondu Sam 2018-01-20 19:45:07

une autre solution, semblable à réponse D'ArtemStorozhuk est d'utiliser le FPS pour passer du domaine frame au domaine time, puis chercher à l'envers en utilisant CV_CAP_PROP_POS_MSEC (qui ne martèle pas le CPU comme CV_CAP_PROP_POS_FRAMES). Voici mon exemple de code qui fonctionne parfaitement sur un .mpg, en utilisant seulement environ 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;
  }
}
2
répondu Trebor Rude 2017-05-23 10:31:02

Oui, c'est possible. Voir le code avec des commentaires:

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

lire Aussi l'article.

1
répondu ArtemStorozhuk 2012-06-29 10:53:37