12

mpeg 圧縮を使用して、Vivotek カメラからのビデオ出力からフレームを読み取るために opencv を使用しています。特定の位置からビデオを開始する関数を使用しようとしています。以下に示すように、 start はスキップするフレーム数です。

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

ただし、開始時のフレームの前に発生する誤ったフレームがキャプチャされているため、これに問題があります。

私はopencvバージョン2.4.2を使用しています

誰かがこの問題を手伝ってくれますか?

4

4 に答える 4

18

少し遅すぎますが、同じトピックを検索しています(Vivotek Cameraに固有ではなく、openCVのmpegの問題について詳しく説明しています):

  • ビデオはエンコードされています
  • OpenCV は FFMPEG を使用します
  • キーフレームを使用するエンコーディング
  • 一部のフレームをスキップすると、エンコーディングで必要な正確なフレームが得られない

同様の質問を参照してください:

  • cvSetCaptureProperty で CV_CAP_PROP_POS_FRAMES を使用して個々のフレームを取得する

  • ビデオ ファイルから 1 つのフレームを取得するにはどうすればよいですか?

  • 次のフレーム番号を設定する CV_CAP_PROP_POS_FRAMES の問題

    desired position        key frame (this is where the cursor will stop)
     |   |                       |                    |
     |   >                       |                    |
     |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
    

    トラックバーでopenCV 2.4.8 / VS2013を使用したサンプルコード:

  • AVI 形式でテスト済み [MPEG4 Video (H264)] : フレーム位置の設定は正常に機能します
  • MPG 形式 [MPEG1/MPEG2] でテスト済み: フレーム位置の設定は正常に機能します

    double currentPos = capture.get(CV_CAP_PROP_POS_FRAMES);
    std::cout << "CV_CAP_PROP_POS_FRAMES = " << currentPos << std::endl;
    
    // position_slider 0 - 100
    double noFrame = position_slider*nbFrames / 100;
    
    // solution 1
    bool success = capture.set(CV_CAP_PROP_POS_FRAMES, noFrame);
    // solution 2
    double frameRate = capture.get(CV_CAP_PROP_FPS);
    double frameTime = 1000.0 * noFrame / frameRate;
    bool success = capture.set(CV_CAP_PROP_POS_MSEC, frameTime);
    
    if (!success) {
        std::cout << "Cannot set frame position from video file at " << noFrame << std::endl;       
        return;
    }
    
    currentPos = capture.get(CV_CAP_PROP_POS_FRAMES);
    if (currentPos != noFrame) {
        std::cout << "Requesting frame " << noFrame << " but current position == " << currentPos << std::endl;
    }
    
    success = capture.read(frame_aux);
    if (!success) {
        std::cout << "Cannot get frame from video file " << std::endl;
        return;
    }
    imshow("test", frame_aux);
    
于 2014-01-26T05:03:43.520 に答える
7

BlouBlou が言ったように、FFMPEG で高圧縮ビデオ フォーマットを読み取る場合、「キー フレーム」技術を使用してビデオをデコードします。そのため、setCV_CAP_PROP_POS_FRAMESプロパティは思い通りに動作しません。

5 つの mpeg ビデオをテストして、それらからすべてのフレームを読み取りました。を使用して合計フレーム数を取得するlong totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);

次に、各ビデオを 2 回読み取ります。1 回目はCV_CAP_PROP_POS_FRAMES0 に設定せず、2 回目は設定します。

CV_CAP_PROP_POS_FRAMES0 に設定すると、ビデオごとに約 10 フレーム、いくつかのフレームがドロップされました。キーフレームがビデオの最初のフレームにないためだと思います。そのため、FFMPEG はいくつかのフレームを最初のキーフレームにスキップします。ただし、.avi などの一部のビデオ フォーマットでは、このような問題は発生しません。私の実際の経験が他の人々の時間を大幅に節約してくれることを願っています (このページを見つけるのに費やした時間は長すぎませんでしたが、十分でした)。

とにかく、CV_CAP_PROP_POS_FRAMESmpeg 形式のビデオに直面しているときに特定のフレームを取得するために使用しないことを強くお勧めします。設定するのは賢明な選択ですCV_CAP_PROP_POS_MSEC:)

于 2016-04-04T12:13:15.007 に答える
3

OpenCV 3.0 にアップグレードする場合は、次の 2 つのユース ケースが役立つ場合があります。これは以前のバージョンでも機能する可能性がありますが、試していません。フレーム a とフレーム b の間のすべてのフレームをキャプチャする場合は、2 番目の使用例を参照して、「desired_frames」を次のように置き換えます。

desired_frames = range(a,b)

まず、いくつかのパッケージをインポートします

import cv2
import math
import numpy as np

n 秒ごとにキャプチャ (ここでは n = 5)

#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()

#################### Setting up parameters ################

seconds = 5
fps = vidcap.get(cv2.CAP_PROP_FPS) # Gets the frames per second
multiplier = fps * seconds

#################### Initiate Process ################

while success:
    frameId = int(round(vidcap.get(1))) #current frame number, rounded b/c sometimes you get frame intervals which aren't integers...this adds a little imprecision but is likely good enough
    success, image = vidcap.read()

    if frameId % multiplier == 0:
        cv2.imwrite("FolderSeconds/frame%d.jpg" % frameId, image)

vidcap.release()
print "Complete"

または、n フレームごとにキャプチャします (ここでは、n = 10)

#################### Setting up the file ################
videoFile = "Jumanji.mp4"
vidcap = cv2.VideoCapture(videoFile)
success,image = vidcap.read()

#################### Setting up parameters ################

#OpenCV is notorious for not being able to good to 
# predict how many frames are in a video. The point here is just to 
# populate the "desired_frames" list for all the individual frames
# you'd like to capture. 

fps = vidcap.get(cv2.CAP_PROP_FPS)
est_video_length_minutes = 3         # Round up if not sure.
est_tot_frames = est_video_length_minutes * 60 * fps  # Sets an upper bound # of frames in video clip

n = 5                             # Desired interval of frames to include
desired_frames = n * np.arange(est_tot_frames) 


#################### Initiate Process ################

for i in desired_frames:
    vidcap.set(1,i-1)                      
    success,image = vidcap.read(1)         # image is an array of array of [R,G,B] values
    frameId = vidcap.get(1)                # The 0th frame is often a throw-away
    cv2.imwrite("FolderFrames/frame%d.jpg" % frameId, image)

vidcap.release()
print "Complete"

それだけです。


いくつかの残念な警告...opencv のバージョン (これは opencv V3 用にビルドされています) によっては、fps 変数を別の方法で設定する必要がある場合があります。詳しくはこちらをご覧ください。バージョンを確認するには、次の手順を実行します。

(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
major_ver
于 2016-04-30T23:47:48.897 に答える
0

不思議なことにassert、目の前に

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

そしてそれを削除しassertて問題を解決しました

于 2020-09-18T11:00:16.123 に答える