I am using following code to display camera feed in Flask web app.
App.py
from flask import Flask, render_template, Response
import cv2
app = Flask(__name__)
camera = cv2.VideoCapture(0)
def gen_frames():
while True:
success, frame = camera.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
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
#app.route('/')
def index():
return render_template('index.html')
#app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
app.run(debug=True)
templates/index.html
<body>
<div>
<img src="{{ url_for('video_feed') }}" width="50%">
</div>
</body>
I want to print frame[0][0][0] value dynamically using commas at the bottom of the video like below.
Video Feed
51, 37, 222, 67, ...
Could you please help me with that?
Thanks in advance
The simplest method is to run JavaScript code with loop which periodically gest this value from server and put value in HTML.
But frame has to be in global variable to access it in another function in flask. And after converting frame to jpg you have to use different variable for this value.
But this method sometimes may have problem with synchromization. It may get value from new frame but browser may still display old frame.
Minimal working code
It uses setInterval(function, 40) to run function every 40ms (which gives 25 executions per second - like 25 frames per second). And this function uses fetch() to get value (JSON) from url /get_value and display it in <div id="value">
EDIT: I use frame[0,0,0].tolist() instead of frame[0,0].tolist() to get only BLUE (cv2 keeps pixel as B,G,R instead of R,G,B). I also add all values to innerText instead of repalcing previous value.
from flask import Flask, render_template_string, jsonify, Response
import cv2
import time
app = Flask(__name__)
camera = cv2.VideoCapture(0)
#success, frame = camera.read() # default value at start
success = False # default value at start
frame = None # default value at start
def gen_frames():
global success
global frame
while True:
success, frame = camera.read() # read the camera frame
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
image = buffer.tobytes() # use other variable instead of `frame`
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n'
b'\r\n' + image + b'\r\n') # concat frame one by one and show result
time.sleep(0.04) # my `Firefox` needs this to have time to display image.
# And this gives stream with 25 FPS (Frames Per Second) (1s/0.04s = 25)
#app.route('/get_value')
def get_value():
#if frame is not None:
if success:
value = frame[0,0,2].tolist()
else:
value = ['?']
#print(value)
return jsonify(value)
#app.route('/')
def index():
return render_template_string('''
<body>
<div>
<img src="{{ url_for('video_feed') }}" width="50%">
</div>
<div id="value"></div>
<script>
place = document.querySelector("#value");
setInterval(function(){
console.log("run function");
fetch("/get_value")
.then(response => response.json())
.then(data => {
if(place.innerText.length > 0){
place.innerText += ",";
}
place.innerText += data;
})
}, 40);
</script
</body>
''')
#app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == "__main__":
try:
app.run(debug=True) #, use_reloader=False)
except KeyboardInterrupt:
print("Stopped by `Ctrl+C`")
finally:
camera.release()
Related
from flask import Flask, Response, request, send_file
from moviepy.editor import VideoFileClip
import socket
import cv2 as cv2
app = Flask(__name__)
video_path = "videos/video.avi"
#app.route('/video_feed/')
def video_feed():
start_frame = int(request.args.get("start_frame"))
end_frame = int(request.args.get("end_frame"))
return Response(gen(start_frame, end_frame), mimetype='multipart/x-mixed-replace; boundary=frame')
def gen(start_frame, end_frame):
cap = cv2.VideoCapture(video_path)
cap.set(1, start_frame)
while True:
success, img = cap.read()
current_frame = cap.get(cv2.CAP_PROP_POS_FRAMES)
if current_frame > end_frame:
break
imgencode = cv2.imencode('.jpg', img)[1]
stringData = imgencode.tobytes()
# can also use tostring()
yield (b'--frame\r\n'
b'Content-Type: text/plain\r\n\r\n' + stringData + b'\r\n')
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8000, debug=True)
So, this is the Flask server I am running. I am able to view the correct frames being yielded by the flask server at this URL: (It doesn't matter that the video playback is too fast)
http://127.0.0.1:8000/video_feed/?start_frame=0&end_frame=5000
But I can't seem to figure out how to use this URL into a development environment like PyCharm to be able to read the frames from this URL into a python script, for example.
url="http://127.0.0.1:8000/video_feed/?start_frame=4000&end_frame=5001"
while True:
resp = urllib.request.urlopen(url)
response = resp.read()
data = resp.split(b'\r\n\r\n', 1)[1]
i = np.frombuffer(data, dtype=np.uint8)
img = cv2.imdecode(i, cv2.IMREAD_UNCHANGED)
cv2.imshow("frame", img)
if cv2.waitKey(16) & 0xFF==ord('q'):
break
cv2.destroyAllWindows()
So this is what I have tried for reading the frames into PyCharm but it only reads the first frame. I want it to be able to ingest all of the frames from the URL. I know that there is something I am not understanding when it comes to URL's or generator functions, so any refactoring or help is greatly appreciated!
On the Flask server side the adjustment is made to the generator function:
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + stringData + b'\r\n')
And then read into an IDE like pycharm as such:
import cv2
vcap = cv2.VideoCapture('http://127.0.0.1:8000/video_feed/?
start_frame=4000&end_frame=5001')
while True:
ret, frame = vcap.read()
if frame is not None:
cv2.imshow('frame', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
else:
print("Frame is None")
break
vcap.release()
cv2.destroyAllWindows()
print("Video stop")
I am making a Flask application to stream 4 camera webcam feeds at once using multithreading based on some code i copied. How can i return the captured camera frame from gen_frames() to display on my website through return Response() below
#camera.route('/video_feed0')
def video_feed0():
#Video streaming route. Put this in the src attribute of an img tag
thread0.start()
return Response(thread0.run(), mimetype='multipart/x-mixed-replace; boundary=frame')
Full Code here:
from flask import Blueprint, render_template, redirect, url_for, request, flash, Response
import cv2
import threading
camera = Blueprint('camera', __name__)
class camThread(threading.Thread):
def __init__(self, previewName, camID):
threading.Thread.__init__(self)
self.previewName = previewName
self.camID = camID
def run(self):
print("Starting " + self.previewName)
gen_frames(self.previewName, self.camID)
yield gen_frames()
def gen_frames(previewName, camID): # generate frame by frame from camera
camerafeed = cv2.VideoCapture(camID)
camerafeed.set(3, 640)
camerafeed.set(4, 480)
print('opening camera 0')
while True:
# Capture frame-by-frame
success, frame = camerafeed.read() # read the camera frame
if not success or camerafeed is None:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
frame = buffer.tobytes()
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
thread0 = camThread("Camera 0", 0)
thread1 = camThread("Camera 1", 1)
thread2 = camThread("Camera 2", 2)
thread3 = camThread("Camera 3", 3)
#camera.route('/camerafeed')
def cameraindex():
return render_template('camera.html')
#camera.route('/video_feed0')
def video_feed0():
#Video streaming route. Put this in the src attribute of an img tag
thread0.start()
return Response(thread0.run(), mimetype='multipart/x-mixed-replace; boundary=frame')
#camera.route('/video_feed1')
def video_feed1():
#Video streaming route. Put this in the src attribute of an img tag
thread1.start()
return Response(thread1.run(), mimetype='multipart/x-mixed-replace; boundary=frame')
#camera.route('/video_feed2')
def video_feed2():
#Video streaming route. Put this in the src attribute of an img tag
thread2.start()
return Response(thread2.run(), mimetype='multipart/x-mixed-replace; boundary=frame')
#camera.route('/video_feed3')
def video_feed3():
#Video streaming route. Put this in the src attribute of an img tag
thread3.start()
return Response(thread3.run(), mimetype='multipart/x-mixed-replace; boundary=frame')
If you want to display the individual feed to the webpage, you can do it inside an img tag in your html page like below:
<img src="{{ url_for('video_feed0') }}"/>
<img src="{{ url_for('video_feed1') }}"/>
<img src="{{ url_for('video_feed2') }}"/>
<img src="{{ url_for('video_feed3') }}"/>
how i can make qrcode scanner in django like this web so i can see the result in text not in image video
i already make the views.py like this
def camera_feed(request):
stream = CameraStream()
frames = stream.get_frames()
return StreamingHttpResponse(frames, content_type='multipart/x-mixed-replace; boundary=frame')
def detect(request):
stream = CameraStream()
success, frame = stream.camera.read()
if success:
status = True
else:
status = False
return render(request, 'detect_barcodes/detect.html', context={'cam_status': status})
my camera_stream.py
class CameraStream(str):
def __init__(self):
self.camera = cv2.VideoCapture(0)
def get_frames(self):
while True:
# Capture frame-by-frame
success, frame = self.camera.read()
if not success:
break
else:
ret, buffer = cv2.imencode('.jpg', frame)
color_image = np.asanyarray(frame)
if decode(color_image):
for barcode in decode(color_image):
barcode_data = (barcode.data).decode('utf-8')
else:
frame = buffer.tobytes()
#hasil2 = b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + barcode_frame + b'\r\n\r\n'
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
this is my urls.py
path('camera_feed', views.camera_feed, name='camera_feed'),
path('detect_barcodes', views.detect, name='detect_barcodes'),
and i use the html like this
<img src="{% url 'qrcode' request.path %}" width="120px" height="120px;">
how i can pass the result in html?
U should use js instascan rather using open cv2 no need to use backend because sever load increases and you easily pas decode value
I have a flask web application which reads one image and display it in my web browser
app.py
from flask import Response
from flask import Flask
from flask import render_template
import cv2
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
def GetImage():
global img
while True:
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + bytearray(img) + b'\r\n')
#app.route("/stream")
def stream():
return Response(GetImage(), mimetype = "multipart/x-mixed-replace; boundary=frame")
if(__name__ == "__main__"):
img = cv2.imread("Cat.jpg", 0)
app.run(debug = True, threaded = True, use_reloader = False)
index.html
<html>
<body>
<img src="{{ url_for('stream') }}">
</body>
</html>
This example doesn´t work, because the image isn´t displayed in the browser.
But when I change GetImage in the following way the image will be displayed in the browser:
def GetImage():
global img
(flag, encodedImage) = cv2.imencode(".jpg", img)
while True:
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' + bytearray(encodedImage) + b'\r\n')
So why do I need this imencode? The image is stored as jpg on my harddisk so why do I have to encode it again as JPG?
If you have JPEG file then you can use standard open() and read() to read it as raw bytes data without decompressing it to array with all pixels - so later you don't have to compress it back to JPEG data using imencode()
img = open("Cat.jpg", "rb").read()
and then you can display it
b'Content-Type: image/jpeg\r\n\r\n'+ img + b'\r\n'
I read it directly in bytes mode - open(..., 'rb') - so I don't have to use bytearray() to convert string to bytes. Besides, reading in text mode it could convert some chars (like "new line") and create incorrect data.
But to send single file you can use send_file()
#app.route("/image")
def image():
return send_file('Cat.jpg')
Working example.
Opening http://127.0.0.1:5000/stream in Chrome it shows image.
My Firefox had problem to display image - it was reading data all time - till I added time.sleep()
I also added version which adds header Content-Length:
from flask import Flask, Response, send_file
import time
app = Flask(__name__)
#app.route("/")
def index():
return "Hello World"
def get_image():
while True:
yield(b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n'+ img + b'\r\n')
time.sleep(0.01) # my Firefox needs some time to display image / Chrome displays image without it
def get_image_with_size():
length = str(len(img)).encode() # convert to bytes
while True:
yield(b'--frame\r\n'
b'Content-Type: image/jpeg\r\n'
b'Content-Length: ' + length + b'\r\n'
b'\r\n'+ img + b'\r\n')
time.sleep(0.01) # my Firefox needs some time to display image / Chrome displays image without it
#app.route("/stream")
def stream():
return Response(get_image(), mimetype="multipart/x-mixed-replace; boundary=frame")
#app.route("/image")
def image():
return send_file('Cat.jpg')
if(__name__ == "__main__"):
img = open('Cat.jpg', 'rb').read()
app.run()
I'm trying to capture two rtsp streams with opencv and then present them with a simple flask server. I can show the two streams together when just using opencv, but when I try to display it through flask it just picks either stream and shows it twice.
Here's the original creators blog
Here is my flask code:
#!/usr/bin/env python
from importlib import import_module
import os
from flask import Flask, render_template, Response
# import camera driver
'''
if os.environ.get('CAMERA'):
Camera = import_module('camera_' + os.environ['CAMERA']).Camera
else:
from camera import Camera
'''
#
from camera_opencv import Camera1, Camera2
app = Flask(__name__)
#app.route('/')
def index():
"""Video streaming home page."""
return render_template('index.html')
def gen(camera):
"""Video streaming generator function."""
while True:
frame = camera.get_frame()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
#app.route('/video_feed1')
def video_feed1():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera1()),
mimetype='multipart/x-mixed-replace; boundary=frame')
#app.route('/video_feed2')
def video_feed2():
"""Video streaming route. Put this in the src attribute of an img tag."""
return Response(gen(Camera2()),
mimetype='multipart/x-mixed-replace; boundary=frame')
if __name__ == '__main__':
app.run(host='0.0.0.0', threaded=True, port=8888)
Here's the camera_opencv file
import cv2
from base_camera import BaseCamera
class Camera1(BaseCamera):
video_source = 0
#staticmethod
def set_video_source(source):
Camera1.video_source = source
#staticmethod
def frames():
camera = cv2.VideoCapture(Camera1.video_source)
if not camera.isOpened():
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img = camera.read()
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
class Camera2(BaseCamera):
video_source = 1
#staticmethod
def set_video_source(source):
Camera2.video_source = source
#staticmethod
def frames():
camera = cv2.VideoCapture(Camera2.video_source)
if not camera.isOpened():
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img = camera.read()
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
Base camera file
import time
import threading
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
class CameraEvent(object):
"""An Event-like class that signals all active clients when a new frame is
available.
"""
def __init__(self):
self.events = {}
def wait(self):
"""Invoked from each client's thread to wait for the next frame."""
ident = get_ident()
if ident not in self.events:
# this is a new client
# add an entry for it in the self.events dict
# each entry has two elements, a threading.Event() and a timestamp
self.events[ident] = [threading.Event(), time.time()]
return self.events[ident][0].wait()
def set(self):
"""Invoked by the camera thread when a new frame is available."""
now = time.time()
remove = None
for ident, event in self.events.items():
if not event[0].isSet():
# if this client's event is not set, then set it
# also update the last set timestamp to now
event[0].set()
event[1] = now
else:
# if the client's event is already set, it means the client
# did not process a previous frame
# if the event stays set for more than 5 seconds, then assume
# the client is gone and remove it
if now - event[1] > 5:
remove = ident
if remove:
del self.events[remove]
def clear(self):
"""Invoked from each client's thread after a frame was processed."""
self.events[get_ident()][0].clear()
class BaseCamera(object):
thread = None # background thread that reads frames from camera
frame = None # current frame is stored here by background thread
last_access = 0 # time of last client access to the camera
event = CameraEvent()
def __init__(self):
"""Start the background camera thread if it isn't running yet."""
if BaseCamera.thread is None:
BaseCamera.last_access = time.time()
# start background frame thread
BaseCamera.thread = threading.Thread(target=self._thread)
BaseCamera.thread.start()
# wait until frames are available
while self.get_frame() is None:
time.sleep(0)
def get_frame(self):
"""Return the current camera frame."""
BaseCamera.last_access = time.time()
# wait for a signal from the camera thread
BaseCamera.event.wait()
BaseCamera.event.clear()
return BaseCamera.frame
#staticmethod
def frames():
""""Generator that returns frames from the camera."""
raise RuntimeError('Must be implemented by subclasses.')
#classmethod
def _thread(cls):
"""Camera background thread."""
print('Starting camera thread.')
frames_iterator = cls.frames()
for frame in frames_iterator:
BaseCamera.frame = frame
BaseCamera.event.set() # send signal to clients
time.sleep(0)
# if there hasn't been any clients asking for frames in
# the last 10 seconds then stop the thread
if time.time() - BaseCamera.last_access > 10:
frames_iterator.close()
print('Stopping camera thread due to inactivity.')
break
BaseCamera.thread = None
Index.html
<html>
<head>
<title>Video Streaming Demonstration</title>
</head>
<body>
<h1>Video Streaming Demonstration</h1>
<img src="{{ url_for('video_feed1') }}">
<img src="{{ url_for('video_feed2') }}">
</body>
</html>
So I kind of managed to make a hackey workaround. For whatever reason I could not resolve, the app just couldn't handle multiple streams individually.
So I changed the camera class and added multiple sources to it and used numpy.hstack(()) to merge both the frames together thus returning one unique stream.
Will be very grateful if someone could help out here as my method is not at all scalable.
import cv2
from base_camera import BaseCamera
import numpy as np
class Camera(BaseCamera):
video_source1 = 0
video_source2 = 1
#staticmethod
def set_video_source(sources):
Camera.video_source1 = sources[0]
Camera.video_source2 = sources[1]
#staticmethod
def frames():
camera1 = cv2.VideoCapture(Camera.video_source1)
camera2 = cv2.VideoCapture(Camera.video_source2)
if not (camera1.isOpened() or camera2.isOpened()):
raise RuntimeError('Could not start camera.')
while True:
# read current frame
_, img1 = camera1.read()
_, img2 = camera2.read()
img1 = cv2.resize(img1, (704, 396))
img2 = cv2.resize(img2, (704, 396))
img = np.hstack((img1, img2))
# encode as a jpeg image and return it
yield cv2.imencode('.jpg', img)[1].tobytes()
According to the blog, I use two generator and send the image to the index.html. And I can see tow streaming.
def generate2():
# it is a generator
global outputFrame2, lock
while True:
with lock:
if outputFrame is None:
continue
(flag, encodedImage2) = cv2.imencode(".jpg", outputFrame2)
if not flag:
continue
yield(b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n' +
bytearray(encodedImage2) + b'\r\n')
And here is videofeed2
#app.route("/video_feed2")
def video_feed2():
return Response(generate2(),
mimetype = "multipart/x-mixed-replace; boundary=frame")