Raoul
Raoul

Reputation: 1892

Playback loop option in OpenCV videos

I am trying to build a playback loop option for an OpenCV video. My program uses Python multiprocessing, and has a button send loopswitch calls through queue4 to enable or disable the loop option. My specific problem is that my video freezes on the last frame, and I would like to know if the line vidFile.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, 1) is a correct use of the cv2.VideoCapture.set() method, and should indeed take the video back to frame 1 and replay it (as I think it should).

EDIT

After revising my code, it now triggers a runtime C++ error, but no other precisions are given. According to this answer, it would seem that using cv2.VideoCapture.set() to jump between frame is buggy. Has anyone managed it anyway?

Thank you,

My code for the capture process (queueand queue2 are in and out queues):

def image_capture(queue, con, queue2, queue4):
    videopath = con.recv()
    vidFile = cv2.VideoCapture(videopath)
    fps = vidFile.get(cv2.cv.CV_CAP_PROP_FPS)
    waitframe = 1/fps
    con.send(waitframe)#sending waitkey duration through pipe to update_image()
    loopswitch = False #init for playing video in a loop 
    while True:
        if queue4.empty():
           pass
        else:
           queueval = queue4.get()
            if queueval=='loop':
               if loopswitch==False:
                  loopswitch = True
               elif loopswitch==True:
                  loopswitch = False
        try:
            flag, frame=vidFile.read()
            if flag==0:
               if loopswitch==False:
                  queue2.put(None)
                  break
               elif loopswitch==True:
                  vidFile.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, 1)
                  continue
            else:                
               queue2.put(frame)
               cv2.waitKey(waitframe)
        except:
            continue

Upvotes: 13

Views: 38193

Answers (5)

Tony
Tony

Reputation: 289

For python3, opencv3.1.0, raspberry pi 3

import numpy as np
import cv2
cap = cv2.VideoCapture('intro.mp4')
while(cap.isOpened()):
    
    ret, frame = cap.read() 
    #cv2.namedWindow("window", cv2.WND_PROP_FULLSCREEN)
    #cv2.setWindowProperty("window",cv2.WND_PROP_FULLSCREEN,cv2.WINDOW_FULLSCREEN)
    
    if ret:
        cv2.imshow("Image", frame)
    else:
       print('no video')
       cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
       continue
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    
    
cap.release()
cv2.destroyAllWindows()

Upvotes: 14

Gilberto Marchiori
Gilberto Marchiori

Reputation: 11

self.cap =cv2.VideoCapture(self.filename)       
while True:

    ret,frameset = self.cap.read()
             
    if self.cap.get(1)>self.cap.get(7)-2:#video loop
        self.cap.set(1,0)#if frame count > than total frame number, next frame will be zero
    cv2.imshow("G",frameset)
    key = cv2.waitKey(1)
    if key == 27:
        break
self.cap.release()
cv2.destroyAllWindows()

Upvotes: 1

joelostblom
joelostblom

Reputation: 48919

I can get looped video playback by using an if statement for when the frame count reaches cap.get(cv2.CAP_PROP_FRAME_COUNT) and then resetting the frame count and cap.set(cv2.CAP_PROP_POS_FRAMES, num) to the same value. The below example keeps looping the video for me.

import cv2

cap = cv2.VideoCapture('path/to/video') 
frame_counter = 0
while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    frame_counter += 1
    #If the last frame is reached, reset the capture and the frame_counter
    if frame_counter == cap.get(cv2.CAP_PROP_FRAME_COUNT):
        frame_counter = 0 #Or whatever as long as it is the same as next line
        cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
    # Our operations on the frame come here
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # Display the resulting frame
    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

It also works to recapture the video instead of resetting the frame count:

if frame_counter == cap.get(cv2.CAP_PROP_FRAME_COUNT):
    frame_counter = 0
    cap = cv2.VideoCapture(video_name)

So at least it works for me to use cap.set(cv2.CAP_PROP_POS_FRAMES, num) to loop a video. What happens if you reset to the zeroth frame instead of the first (like with the avi method)?

Upvotes: 4

Felipe Gutierrez
Felipe Gutierrez

Reputation: 695

For the C++ guys:

void openVideo() {
    cap.open(videoName);
    if (!cap.isOpened()) {
        std::cout << "Video file not loaded!" << std::endl;
    }

    numberOfFrames = (int)cap.get(cv::CAP_PROP_FRAME_COUNT);

    //--- GRAB AND WRITE LOOP
    std::cout << "Start grabbing" << std::endl
        << "Press any key to terminate" << std::endl;
    for (;;)
    {
        // wait for a new frame from camera and store it into 'frame'
        cap.read(frame);
        frameCounter++;
        // check if we succeeded
        if (frameCounter == numberOfFrames) {
            frameCounter = 0;
            cap.set(cv::CAP_PROP_POS_FRAMES, 0);
        }
        if (frame.empty()) {
            std::cerr << "ERROR! blank frame grabbed\n";
            break;
        }
        // show live and wait for a key with timeout long enough to show images
        cv::imshow("Live", frame);
        if (cv::waitKey(5) >= 0)
            break;
    }
    // the camera will be deinitialized automatically in VideoCapture destructor
}

Upvotes: 0

Raoul
Raoul

Reputation: 1892

I partially solved it by replacing vidFile.set (cv2.cv.CV_CAP_PROP_POS_FRAMES, 1) by vidFile.set(cv2.cv.CV_CAP_PROP_POS_AVI_RATIO, 0), although this works for .avi files only.

Upvotes: 4

Related Questions