I need to send realtime image RGB data (in Numpy format) to a HTML page in a browser (web-based GUI), through HTTP.
The following code works with the well-known multipart/x-mixed-replace
trick: run this and access http://127.0.0.1:5000/video_feed: you will see a video in the browser.
from flask import Flask, render_template, Response
import numpy as np, cv2
app = Flask('')
def gen_frames():
while True:
img = np.random.randint(0, 255, size=(1000, 1000, 3))
ret, buf = cv2.imencode('.jpg', img)
frame = buf.tobytes()
yield (b'--frame\r\nContent-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
@app.route('/video_feed')
def video_feed():
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
app.run()
However, according to my benchmark, the real performance bottleneck is the cv2.imencode('.jpg', img)
.
In my real application, if I just generate the image, the CPU is ~ 1% for Python.
When I imencode(...)
, the CPU jumps to 25%, and 15% for Chrome.
I also tried with PNG format but it's similar.
Question: how to efficiently send RGB image data from a numpy array (example: 1000 x 1000 pixels x 3 colors because of RGB) to a browser HTML page?
(Without compression/decompression it might be better, but how?)
Here is the benchmark
FPS CPU PYTHON CPU CHROME
PNG 10.8 20 % 10 %
JPG 14 23 % 12 %
JPG 10.7 16 % 10 % (with time.sleep to match PNG 10.8 fps)
BMP 19 17 % 23 %
BMP 10.8 8 % 12 % (with time.sleep to match PNG 10.8 fps)