16

OpenCVでビデオを逆再生することは可能ですか?API呼び出しによって、またはビデオフレームをバッファリングし、順序を逆にして新しいビデオファイルにすることによって。

ありがとう

4

3 に答える 3

20

これを行う唯一の実用的な方法は、フレームを手動で抽出し、それらを(メモリまたはファイルに)バッファリングしてから、逆の順序でリロードすることです。

問題は、ビデオコンプレッサーがすべて時間の冗長性を利用していることです。つまり、2つの連続するフレームはほとんどの場合非常に似ています。したがって、それらは時々(通常は数百フレームごとに)完全なフレームをエンコードし、前と現在の違いのみを送信します。

ここで、デコードを機能させるには、同じ順序で実行する必要があります。キーフレーム(完全なもの)をデコードしてから、新しいフレームごとに差を追加して、現在の画像を取得します。

この戦略により、ビデオでの逆再生が非常に困難になります。いくつかの手法がありますが、すべてバッファリングが含まれます。

これで、Astorによって記述されたCV_CAP_PROP_POS_FRAMESパラメーターを見たことがあるかもしれません。問題はないようですが、上記の問題のため、OpenCVは特定のフレームに正しくジャンプできません(これらの問題には複数のバグがあります)。彼ら(OpenCV開発者)はいくつかのソリューションに取り組んでいますが、それらでも非常に遅くなります(前のキーフレームに戻ってから、選択したキーフレームにデコードする必要があります)。この手法を使用する場合、各フレームは平均して数百回デコードする必要があり、非常に遅くなります。それでも、それは機能しません。

編集 バッファを逆にする方法を追求する場合、デコードされたビデオは通常のコンピュータのメモリリソースをすぐに使い果たしてしまうことに注意してください。1分間の通常の720pビデオは、解凍時に4.7GBのメモリを必要とします。フレームを個別のファイルとしてディスクに保存することは、この問題の実用的な解決策です。

于 2012-06-29T11:19:10.397 に答える
2

Another solution, similar to ArtemStorozhuk's answer is to use the FPS to move from the frame domain into the time domain, then seek backwards using CV_CAP_PROP_POS_MSEC (which doesn't hammer the CPU like CV_CAP_PROP_POS_FRAMES can). Here's my sample code, which works perfectly on an .mpg, using only about 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;
  }
}
于 2013-06-01T19:48:34.550 に答える
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;
    }
}

この記事も読んでください。

于 2012-06-29T10:53:37.630 に答える