利用flask將opencv實時視頻流輸出到瀏覽器

opencv經過webcam能夠獲取本地實時視頻流,可是若是須要將視頻流共享給其餘機器調用,就能夠將利用flask框架構建一個實時視頻流服務器,而後其餘機器能夠經過向這個服務器發送請求來獲取這臺機器上的實時視頻流。[這篇文章](https://blog.miguelgrinberg.com/post/video-streaming-with-flask)包含很是詳細的理論介紹和具體實現,力薦!html

首先須要說明的是這裏flask提供視頻流是經過generator函數進行的,不瞭解的能夠去查下文檔這裏就不具體講了。flask經過將一連串獨立的jpeg圖片輸出來實現視頻流,這種方法叫作motion JPEG,好處是延遲很低,可是成像質量通常,由於jpeg壓縮圖片的質量對motion stream不太夠用。python

multipart 模式

想要將後一次請求獲得的圖片覆蓋到前一次從而達到動畫的效果就須要使用在response的時候使用multipart模式。Multipart response由如下幾部分組成:包含multipart content類型的header,分界符號分隔的各個part,每一個part都具備特定的content類型。multipart視頻流的結構以下:git

HTTP/1.1 200 OK
Content-Type: multipart/x-mixed-replace; boundary=frame

--frame
Content-Type: image/jpeg

<jpeg data here>
--frame
Content-Type: image/jpeg

<jpeg data here>
...

flask server

具體實現代碼main.pygithub

from flask import Flask, render_template, Response
import opencv

class VideoCamera(object):
    def __init__(self):
        # 經過opencv獲取實時視頻流
        self.video = cv2.VideoCapture(0) 
    
    def __del__(self):
        self.video.release()
    
    def get_frame(self):
        success, image = self.video.read()
        # 由於opencv讀取的圖片並不是jpeg格式,所以要用motion JPEG模式須要先將圖片轉碼成jpg格式圖片
        ret, jpeg = cv2.imencode('.jpg', image)
        return jpeg.tobytes()

app = Flask(__name__)

@app.route('/')  # 主頁
def index():
    # jinja2模板,具體格式保存在index.html文件中
    return render_template('index.html')

def gen(camera):
    while True:
        frame = camera.get_frame()
        # 使用generator函數輸出視頻流, 每次請求輸出的content類型是image/jpeg
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

@app.route('/video_feed')  # 這個地址返回視頻流響應
def video_feed():
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')   

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, port=5000)

index.htmlweb

<html>
  <head>
    <title>Video Streaming Demonstration</title>
  </head>
  <body>
    <h1>Video Streaming Demonstration</h1>
    <img src="{{ url_for('video_feed') }}">
  </body>
</html>

注:圖片地址由大括號內的字典給出,指向app的第二個地址video_feed,在multipart模式下瀏覽器會將每次請求獲得的地址對大括號進行更新。flask

侷限性

若是視頻流一直存在的話,這個app能輸出視頻流的的客戶端的數量和web worker的數量相同,在debug模式下,這個數量是1,也就是說只有一個瀏覽器上可以看到視頻流輸出。
若是要克服這種侷限的話,使用基於協同網絡服務的框架好比gevent,能夠用一個worker線程服務多個客戶端。瀏覽器

參考

https://blog.miguelgrinberg.com/post/video-streaming-with-flask
https://github.com/mattmakai/video-service-flask
http://www.chioka.in/python-live-video-streaming-example/服務器

相關文章
相關標籤/搜索