How to process images of a video, frame by frame, in video streaming using OpenCV and Python
Solution 1
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
Solution 2
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
Solution 3
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.
Solution 4
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;
}
Solution 5
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!
Mehran
Updated on July 09, 2022Comments
-
Mehran almost 2 years
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 returnFalse
! And it won't capture frames anymore, even if I wait for a long time. -
Mehran over 10 yearsThank 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?
-
user2239318 over 10 years@Mehran would you be so gentle to share the python version?
-
Gulzar almost 8 yearsThis works, but at some random point the frames stop comin alhough the input stream continues. Something still gets hanged here
-
JohnAllen over 7 yearsThis doesn't answer the question.
-
Richard over 7 yearsIncluding a link to further information would have been appreciated.
-
Captain Fantastic over 6 yearsI believe your last line should be:
cv2.destroyAllWindows()
-
Mehran over 6 yearsNice 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.
-
Alexander Lysenko over 6 yearsIt doesn't drop the performance - it drops few frames. There is no lugging or something similar, so this worked for us.
-
Mehran about 6 yearsThis 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.
-
Rohan Pillai about 5 yearsFor OpenCV 3.0 onwards, change
cap.get(cv2.cv.CV_CAP_PROP_POS_FRAMES)
tocap.get(cv2.CAP_PROP_POS_FRAMES)
. -
Bahae El Hmimdi almost 3 yearsyou must add if not ret: continue
-
Batselot over 2 yearsWhat is your count doing here?
-
Bahae El Hmimdi over 2 yearscounting number of frames proceeded.
-
Batselot over 2 yearsOh okay, you weren't using them(printing or returning them) so I thought maybe you were doing something else with the count.