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
CodePudding user response:
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()