I've implemented a system to capture faces on-the-fly from a live stream using flask and OpenCV. I'm now facing difficulties with closing the stream and releasing the VideoCapture
object. Here is a snippet of my code below:
from flask import Flask, Response, render_template
import cv2, imutils
import face_recognition
from skimage.exposure import is_low_contrast
app = Flask(__name__)
cam_feed = cv2.VideoCapture(0) # to get feed from webcam, use 0 as argument
def gen_frames(): # generate frame by frame from camera
"""
Variable for counting number of images collected
List for saving encodings also declared here
"""
image_counter = 0
name = "John Doe"
known_names = []
known_encodings = []
if not cam_feed.isOpened():
print("Cannot open camera")
exit()
while True:
# Capture frame-by-frame
success, frame = cam_feed.read() # read the camera frame
if not success:
print("Can't receive frame (stream end?). Exiting ...")
break
else:
ret, frame = cam_feed.read()
frame = imutils.resize(frame, width=640)
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# Our operations on the frame come here
else:
# face location model can either be HOG or CNN but HOG is faster (but less accurate) and way better if you don't have a GPU
boxes = face_recognition.face_locations(frame, model='hog')
if boxes: # if a face is detected
for (top, right, bottom, left) in boxes:
if (image_counter < 20):
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
encodings = face_recognition.face_encodings(frame, boxes)
known_names.append(name)
known_encodings.append(encodings)
image_counter += 1
else:
break # break while True loop and end stream
ret, buffer = cv2.imencode('.jpg', frame) # encode the frame so that flask can return it as a response in bytes format
frame = buffer.tobytes() # convert each frame to a byte object
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n') # concat frame one by one and show result
Here are my routes for streaming:
@app.route('/video_feed')
def video_feed():
#Video streaming route. Put this in the src attribute of an img tag
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
When my image count reaches 20, the loop doesn't seem to break because I can see my webcam is still functioning. What I've tried to do is to create another route where I call cam_feed.release()
and I add the route using the link in my index.html
file; here is the code:
@app.route('/done')
def done():
if cam_feed.isOpened():
print("Releasing cam feed")
cam_feed.release()
return "Done"
and finally, here is the code that runs the flask server:
if __name__ == '__main__':
app.run(debug=True)
My question is this: How can I stop the stream and turn off my webcam after I'm done collecting the images? Thanks.