58

I am a beginner in OpenCV. I want to do some image processing on the frames of a video which is being uploaded to my server. I just want to read the available frames and write them in a directory. Then, wait for the other part of the video to be uploaded and write the frames to the directory. And , I should wait for each frame to be completely uploaded then write it to a file.

Can you tell me how can I do it with OpenCV (Python)?

Edit 1: I wrote this code for capturing the video from a file, while new data are being appended at the end of the file. In other words, the out.mp4 file is not a complete video and another program is writing new frames on it. What I'm going to do is, wait for the other program to write new frames then read them and display them.

Here is my code:

import cv2
cap = cv2.VideoCapture("./out.mp4")

while True:
    if cap.grab():
        flag, frame = cap.retrieve()
        if not flag:
            continue
        else:
            cv2.imshow('video', frame)
    if cv2.waitKey(10) == 27:
        break

So the problem is the cap.grab() call! When there is no frame, it will return False! And it won't capture frames anymore, even if I wait for a long time.

Joel G
  • 25
  • 2
  • 7
Mehran
  • 1,951
  • 4
  • 20
  • 26
  • Please add a more detailed description. 'some image processing on the frames' during the upload or after? 'available frames' where and how they should be available? 'Wait for other part of the video' so just appending?... – Robert Caspary Sep 23 '13 at 10:31
  • @RobertCaspary thank you for your comment. 'some image processing on the frames': just assume that I want to write the frame into a file in a directory. 'available frames': suppose that the video has 100 frames, but just 40 of the frames are uploaded, so available frames are the first 40 frames. And so far, I have saved them into files in a specific directory. 'Wait for other part of the video': wait for the 41st frame to be uploaded then save it to another file, then the 42nd frame, and so on. Is it clear? – Mehran Sep 23 '13 at 19:18

7 Answers7

63

After reading the documentation of VideoCapture. I figured out that you can tell VideoCapture, which frame to process next time we call VideoCapture.read() (or VideoCapture.grab()).

The problem is that when you want to read() a frame which is not ready, the VideoCapture object stuck on that frame and never proceed. So you have to force it to start again from the previous frame.

Here is the code

import cv2

cap = cv2.VideoCapture("./out.mp4")
while not cap.isOpened():
    cap = cv2.VideoCapture("./out.mp4")
    cv2.waitKey(1000)
    print "Wait for the header"

pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
while True:
    flag, frame = cap.read()
    if flag:
        # The frame is ready and already captured
        cv2.imshow('video', frame)
        pos_frame = cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
        print str(pos_frame)+" frames"
    else:
        # The next frame is not ready, so we try to read it again
        cap.set(cv2.cv.CV_CAP_PROP_POS_FRAMES, pos_frame-1)
        print "frame is not ready"
        # It is better to wait for a while for the next frame to be ready
        cv2.waitKey(1000)

    if cv2.waitKey(10) == 27:
        break
    if cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES) == cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT):
        # If the number of captured frames is equal to the total number of frames,
        # we stop
        break
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
Mehran
  • 1,951
  • 4
  • 20
  • 26
  • This works, but at some random point the frames stop comin alhough the input stream continues. Something still gets hanged here – Gulzar May 29 '16 at 12:34
  • 6
    For OpenCV 3.0 onwards, change `cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)` to `cap.get(cv2.CAP_PROP_POS_FRAMES)`. – Rohan Pillai Feb 11 '19 at 09:41
27

Use this:

import cv2
cap = cv2.VideoCapture('path to video file')
count = 0
while cap.isOpened():
    ret,frame = cap.read()
    cv2.imshow('window-name', frame)
    cv2.imwrite("frame%d.jpg" % count, frame)
    count = count + 1
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows() # destroy all opened windows
NG_
  • 6,895
  • 7
  • 45
  • 67
prtkp
  • 537
  • 1
  • 6
  • 8
10

According to the latest updates for OpenCV 3.0 and higher, you need to change the Property Identifiers as follows in the code by Mehran:

cv2.cv.CV_CAP_PROP_POS_FRAMES

to

cv2.CAP_PROP_POS_FRAMES

and same applies to cv2.CAP_PROP_POS_FRAME_COUNT.

Hope it helps.

srihegde
  • 358
  • 3
  • 8
7

In openCV's documentation there is an example for getting video frame by frame. It is written in c++ but it is very easy to port the example to python - you can search for each fumction documentation to see how to call them in python.

#include "opencv2/opencv.hpp"

using namespace cv;

int main(int, char**)
{
    VideoCapture cap(0); // open the default camera
    if(!cap.isOpened())  // check if we succeeded
        return -1;

    Mat edges;
    namedWindow("edges",1);
    for(;;)
    {
        Mat frame;
        cap >> frame; // get a new frame from camera
        cvtColor(frame, edges, CV_BGR2GRAY);
        GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
        Canny(edges, edges, 0, 30, 3);
        imshow("edges", edges);
        if(waitKey(30) >= 0) break;
    }
    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}
zenpoy
  • 19,490
  • 9
  • 60
  • 87
  • Thank you very much for your answer. I did this in python. But the problem is, when you call cap>>frame; it doesn't wait for the frame to completely ready! So if the frame is not ready, then it will return null. And after that, it doesn't capture any other frames. Does it make sense? – Mehran Sep 25 '13 at 01:34
  • 5
    @Mehran would you be so gentle to share the python version? – user2239318 Jan 23 '14 at 13:52
2

This is how I would start to solve this:

  1. Create a video writer:

    import cv2.cv as cv
    videowriter = cv.CreateVideoWriter( filename, fourcc, fps, frameSize)
    

    Check here for valid parameters

  2. Loop to retrieve[1] and write the frames:

    cv.WriteFrame( videowriter, frame )
    

    WriteFrame doc

[1] zenpoy already pointed in the correct direction. You just need to know that you can retrieve images from a webcam or a file :-)

Hopefully I understood the requirements correct.

Robert Caspary
  • 1,584
  • 9
  • 7
2

The only solution I have found is not to set the index to a previous frame and wait (then OpenCV stops reading frames, anyway), but to initialize the capture one more time. So, it looks like this:

cap = cv2.VideoCapture(camera_url)
while True:
    ret, frame = cap.read()

    if not ret:
        cap = cv.VideoCapture(camera_url)
        continue

    # do your processing here

And it works perfectly!

  • Nice solution. But, what's the overhead of reinitializing the Capture? we need to be sure that destroying the object and creating it doesn't drop the performance. – Mehran Dec 02 '17 at 19:43
  • It doesn't drop the performance - it drops few frames. There is no lugging or something similar, so this worked for us. – Alexander Lysenko Dec 06 '17 at 13:18
  • This solution works when the stream (in this case, Camera) always starts from the current frame. In my case, the file is being uploaded to the server and saved to out.mp4. So if I reinitialize the Video capture, it will start from the first frame of the video not the last available frame. – Mehran Feb 15 '18 at 18:41
0

This is example where a.mp4 is the video file

import cv2
cap = cv2.VideoCapture('a.mp4')
count = 0
while cap.isOpened():
    ret,frame = cap.read()
    if not ret:
        continue
    cv2.imshow('window-name', frame)
    #cv2.imwrite("frame%d.jpg" % count, frame)
    count = count + 1
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
Bahae El Hmimdi
  • 364
  • 1
  • 5