Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Opencv VideoCapture set CV_CAP_PROP_POS_FRAMES not working

Tags:

opencv

I am using opencv to read frames from a video output from a Vivotek Camera using the mpeg compression. I am trying to use the function to start the video from a particular position., shown below where start is the number of frames I want to skip.

inputVideo.set(CV_CAP_PROP_POS_FRAMES, start); 

However I am having a problem with this as the incorrect frame is being captured which happens before the frame at start.

I am using opencv version 2.4.2

Can someone please help with this issue?

like image 475
user461426 Avatar asked Oct 16 '13 13:10

user461426


3 Answers

If you're willing to upgrade to OpenCV 3.0 the following 2 use cases may be help you. This may work for earlier versions, but I haven't tried. If you want it to capture all the frames between frame a and frame b, refer to the 2nd use case and replace "desired_frames" with:

desired_frames = range(a,b)

First, import some packages

import cv2
import math
import numpy as np

Capture every n seconds (here, 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"

Alternatively, capture every n frames (here, 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"

That's pretty much it.


Some unfortunante caveats...depending on your version of opencv (this is built for opencv V3), you may need to set the fps variable differently. See here for details. To find out your version, you can do the following:
(major_ver, minor_ver, subminor_ver) = (cv2.__version__).split('.')
major_ver
like image 51
Afflatus Avatar answered Nov 16 '22 05:11

Afflatus


A bit too late but searching on same topic (not specific to Vivotek Camera but more on mpeg problem with openCV) :

  • Video is encoded
  • OpenCV uses FFMPEG
  • Encoding use key frames
  • When skipping some frames encoding can't give you the exact frame you want

see similar question :

  • Getting individual frames using CV_CAP_PROP_POS_FRAMES in cvSetCaptureProperty

  • How can I get one single frame from a video file?

  • Problem with CV_CAP_PROP_POS_FRAMES setting next frame number

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

    Sample code using openCV 2.4.8 / VS2013 with trackbar :

  • tested with AVI format [MPEG4 Video (H264)] : setting frame position works fine
  • tested with MPG format [MPEG1/MPEG2] : setting frame position works fine

    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);
    
like image 24
BlouBlou Avatar answered Nov 16 '22 06:11

BlouBlou


Just as BlouBlou said, when you read some high compression video format with FFMPEG, it used "key frame" technology to decode video. So set CV_CAP_PROP_POS_FRAMES property will not work as you want.

I tested 5 mpeg videos to read all frames from them. Get total frame count using long totalFrameNumber = capture.get(CV_CAP_PROP_FRAME_COUNT);

Then I read each video twice, first time not set CV_CAP_PROP_POS_FRAMES to 0, second time set it.

It did drop some frames when you set CV_CAP_PROP_POS_FRAMES to 0, about 10 frames each video. I guess because the key frame is not in the first frame of the video, so FFMPEG skip some frames to the first key frame. But some video format such as .avi won't appear such problem. I hope my real experience will save other people much time (well I spent to find this page not too long but enough).

Anyway, highly recommend not to using CV_CAP_PROP_POS_FRAMES to get a specific frame when you face mpeg format video. It is a smart choice to set CV_CAP_PROP_POS_MSEC:)

like image 25
very hit Avatar answered Nov 16 '22 06:11

very hit