I would like to create a function that reads frames from an HTTP stream using requests and returns each frame. But because of the fact that the stream reader is based on an iterator object (if I understand correctly), returning a frame is breaking the stream.
The code I am using (works perfectly fine, from this answer):
import cv2
import requests
import numpy as np
r = requests.get('http://roofcam.warwick.ac.uk/cgi-bin/faststream.jpg', stream=True)
if(r.status_code == 200):
bytes_buffer = bytes()
for chunk in r.iter_content(chunk_size=1024):
bytes += chunk
a = bytes_buffer.find(b'\xff\xd8')
b = bytes_buffer.find(b'\xff\xd9')
if a != -1 and b != -1:
jpg = bytes_buffer[a:b+2]
bytes_buffer = bytes_buffer[b+2:]
i = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('i', i)
if cv2.waitKey(1) == 27:
exit(0)
else:
print("Received unexpected status code {}".format(r.status_code))
Concept of what I'd like to do (with the return that I'd like to work if it was a while function instead of a for using iterator):
import cv2
import requests
import numpy as np
r = requests.get('http://roofcam.warwick.ac.uk/cgi-bin/faststream.jpg', stream=True)
def get_frame_from_stream(r):
if(r.status_code == 200):
bytes_buffer = bytes()
for chunk in r.iter_content(chunk_size=1024):
bytes_buffer += chunk
a = bytes_buffer.find(b'\xff\xd8')
b = bytes_buffer.find(b'\xff\xd9')
if a != -1 and b != -1:
jpg = bytes_buffer[a:b + 2]
bytes_buffer = bytes_buffer[b + 2:]
i = cv2.imdecode(np.fromstring(
jpg, dtype=np.uint8), cv2.IMREAD_COLOR)
return i
else:
print("Received unexpected status code {}".format(r.status_code))
return None
while True:
if img is not None:
img = get_frame_from_stream(r)
cv2.imshow('i', img)
cv2.waitKey(0)
else:
break
So basically I'd like to return each frame where the original code is displaying the frame so that I can perform some processing on it. But I don't understand how exactly is the iter_content allowing the original code to work continuously.
(I didn't know how to name the question - will welcome a better title)
Python has a very beautiful concept of
generators
, which may be the thing you are looking for, so basically to fabricate agenerator
we use keywordyield
instead ofreturn
. The basic difference between these two keywords is that thereturn
statement simply halts the function execution once encountered, while on the other handyield
keyword let's the execution to continue and keeps on generating value until alive. It can be visualized in a simple example as:If We would had reproduce the same scenario using
return
statement then it may look like:So in the above code if you replace the
return
keyword withyield
, then you can iterate the frames as:There is no need of a
while
loop is this case, unless and until this stream is alive, the method would keep on generating frames.