I've had success in Python 3 using a simple counter and setting the capture to that counter's frame, as follows:
import cv2
cap = cv2.VideoCapture('XYZ.avi')
# For streams:
# cap = cv2.VideoCapture('rtsp://url.to.stream/media.amqp')
# Or e.g. most common ID for webcams:
# cap = cv2.VideoCapture(0)
count = 0
while cap.isOpened():
ret, frame = cap.read()
if ret:
cv2.imwrite('frame{:d}.jpg'.format(count), frame)
count += 30 # i.e. at 30 fps, this advances one second
cap.set(cv2.CAP_PROP_POS_FRAMES, count)
else:
cap.release()
break
I've tried to find a way to make this a little more pythonic using a with statement but I don't believe the CV2 library has been updated for it.
python - OpenCV - How to get only first frame and skip other frames when servo function is called - Stack Overflow
c++ - Reading every nth frame from VideoCapture in OpenCV - Stack Overflow
python - Skip frames and seek to end of RTSP stream in OpenCV - Stack Overflow
[Question] How to capture a picture after every 5 seconds of camera using opencv python and Raspbery Pi 3?
I've had success in Python 3 using a simple counter and setting the capture to that counter's frame, as follows:
import cv2
cap = cv2.VideoCapture('XYZ.avi')
# For streams:
# cap = cv2.VideoCapture('rtsp://url.to.stream/media.amqp')
# Or e.g. most common ID for webcams:
# cap = cv2.VideoCapture(0)
count = 0
while cap.isOpened():
ret, frame = cap.read()
if ret:
cv2.imwrite('frame{:d}.jpg'.format(count), frame)
count += 30 # i.e. at 30 fps, this advances one second
cap.set(cv2.CAP_PROP_POS_FRAMES, count)
else:
cap.release()
break
I've tried to find a way to make this a little more pythonic using a with statement but I don't believe the CV2 library has been updated for it.
I'm afraid there's not much you can do and it's not just a shortcoming of OpenCV. You see, modern video codecs, are, generally, complex beasts. To get a higher compression rate the encoding of a frame is often dependent on previous and sometimes even successive frames.
So, most of the time you have to decode frames before the desired one even if you don't need them.
There are rather non-trivial tricks to specifically encode a video file, so that it would be cheap to get every Nth frame, but it's not feasible in general case.
That said, you can try the seeking functionality OpenCV provides (see OpenCV Seek Function/Rewind). It may (as well as may not) work faster depending on the circumstances. However, personally, I wouldn't bet on it.
Try this:
vcap = cv2.VideoCapture("rtspsrc location=rtsp://{IPcam}/12 ! decodebin ! videoconvert ! appsink max-buffers=1 drop=true")
This uses gstreamer to grab your camera feed, and will maintain a buffer of length 1 and drop the oldest as new incoming frames are received. Then, every time you call vcap.read() you should get the latest frame.
You can also try using the OMX decoder on the Raspberry Pi if you notice CPU usage is really high, as this will decode the video (assuming it's h264) on the GPU: ! rtph264depay ! h264parse ! omxh264dec ! appsink max-buffers=1 drop=true
You may need to recompile OpenCV as by default it's compiled with FFMPEG support, not gstreamer. This is fairly simple, just pass -D WITH_GSTREAMER=ON -D WITH_FFMPEG=OFF to the cmake command. Make sure you have the gstreamer development libs installed apt install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev.
I rewrote threading implementation from Shubham into a class, to be able to stream many cameras:
import threading
from threading import Lock
import cv2
class Camera:
last_frame = None
last_ready = None
lock = Lock()
def __init__(self, rtsp_link):
capture = cv2.VideoCapture(rtsp_link)
thread = threading.Thread(target=self.rtsp_cam_buffer, args=(capture,), name="rtsp_read_thread")
thread.daemon = True
thread.start()
def rtsp_cam_buffer(self, capture):
while True:
with self.lock:
self.last_ready, self.last_frame = capture.read()
def getFrame(self):
if (self.last_ready is not None) and (self.last_frame is not None):
return self.last_frame.copy()
else:
return None
Then, it can be used as:
capture = Camera('rtsp://...')
while True:
frame = capture.getFrame()
I am working on a school project which is related to Image Processing using OpenCV Python and Raspberry Pi 3.
The hardware of Raspberry Pi 3 cannot handle the video from camera consecutively, therefore I'm thinking about only capture a picture after every 5 seconds from the camera and use it to recognize what I need, then continue.
I did some research on the internet and found a function called time.sleep(5), however this function only pause the camera 5 seconds and then continue.
Can anyone help me to solve my problem. Thank you so much. Sorry for my bad English, here is my code so far. In my code, I use a video to test first, then when figure out the solution, I will apply on camera.
import cv2
import numpy as np
import time
headcc = cv2.CascadeClassifier('lib/heads_cascade.xml')
cap = cv2.VideoCapture('image/hockey_game.avi')
def video():
ret, frame = cap.read()
# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
head = headcc.detectMultiScale(frame, 1.2, 2, 0 , (20, 20), (40, 40))
print type(head)
print head
print head.shape
print "Number of heads detected: " + str(head.shape[0])
if len(head) > 0:
for (x, y, w, h) in head:
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 255), 1)
cv2.rectangle(frame, ((0,frame.shape[0] -25)),(270, frame.shape[0]), (255,255,255), -1)
cv2.putText(frame, "Number of head detected: " + str(head.shape[0]), (0,frame.shape[0] -10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0,0,0), 1)
cv2.namedWindow('Camera',cv2.WINDOW_NORMAL)
cv2.imshow('Camera',frame)
while(cap.isOpened()):
video()
time.sleep(5)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()Update March 15th, 2018: Thanks to comment from Joe, I have found the way to skip frames. However, the program still cannot know whether the video ends, and also the fps code still appear 0.0. So if there is any help for these errors, I will really appreciate. Here is the code so far:
import cv2
import numpy as np
import time
headcc = cv2.CascadeClassifier('lib/heads_cascade.xml')
cap = cv2.VideoCapture('image/hockey_game.avi')
fps = cap.get(cv2.CAP_PROP_POS_FRAMES)
def video():
ret, frame = cap.read()
# gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
head = headcc.detectMultiScale(frame, 1.2, 2, 0 , (20, 20), (40, 40))
# print type(head)
# print head
# print head.shape
print "Number of heads detected: " + str(head.shape[0])
if len(head) > 0:
for (x, y, w, h) in head:
cv2.rectangle(frame, (x,y), (x+w, y+h), (0, 255, 255), 1)
# cv2.rectangle(frame, ((0,frame.shape[0] -25)),(270, frame.shape[0]), (255,255,255), -1)
# cv2.putText(frame, "Number of head detected: " + str(head.shape[0]), (0,frame.shape[0] -10), cv2.FONT_HERSHEY_TRIPLEX, 0.5, (0,0,0), 1)
cv2.namedWindow('Camera',cv2.WINDOW_NORMAL)
cv2.imshow('Camera',frame)
while(cap.isOpened()):
video()
cf = cap.get(cv2.CAP_PROP_POS_FRAMES) - 1
cap.set(cv2.CAP_PROP_POS_FRAMES, cf+50)
# cv2.setTrackbarPos("pos_trackbar", "Frame Grabber",
int(cap.get(cv2.CAP_PROP_FPS)))
time.sleep(2)
if (cv2.waitKey(1) & 0xFF == ord('q')):
break
print fps
cap.release()
cv2.destroyAllWindows()