建立 MJPEG 即時影像串流
這篇教學會介紹 False 與 mjpeg-streamer 兩種建立 MJPEG 即時影像串流的方法,讓電腦攝影機變成遠端攝影機,使用類似 CCTV 監視器影像的方式傳送 MJPEG 影像串流。
延伸參考:爬取交通部 CCTV 即時影像
快速導覽:
認識 MJPEG 影像串流
MJPEG 或 Motion JPEG ( Motion Joint Photographic Experts Group ) 是一種影像壓縮格式,可以將串流影片的每一幀壓縮為 JPEG 圖片進行傳送,這種傳輸模式不僅大幅減少了資料傳輸量,更提高了解壓縮的效率,這種影像串流的技術常用於物聯網設備的攝影機、監視器、微控制器等應用情境,由於是傳輸 JPEG,因此傳輸過程中「無法傳輸聲音」並會產生「失真壓縮」。
MJPEG 的傳輸屬於「多部分回應 Multipart Responses」,過程中每個影格都被獨立壓縮成 JPEG 格並以一個獨立部分 ( part ) 的形式存在,Multipart Responses 使用 Content-Type 來傳輸資料,在 MJPEG 的情況下,Content-Type 通常是「
multipart/x-mixed-replace
」,表示每個部分之間的分隔符號,用來區分不同的影格。
MJPEG 影像串流的結構如下:Content-Type 標頭為「multipart/x-mixed-replace
」並定義邊界字串 boundary 為「frame
」,接著每個部分以「--frame
」為前綴,並具有自己的 Content-Type 標頭。
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
了解 MJPEG 影像串流的結構之後,就能透過 Flask 搭配 OpenCV,建立可以即時傳輸串流影像的簡單網頁,首先安裝 Flask 和 OpenCV。
pip install flask, opencv-python
使用下方的程式碼,使用 Flask 建立一個簡單的網頁,當網頁開啟後,裡面會放入一張路徑為「/mjpeg
」的圖片,讀取圖片時,會發送另外一個 http request 執行 mjpeg 函式,函式內容根據上述的「多部分回應 Multipart Responses」結構,發送 MJPEG 的內容。
from flask import Flask, Response
import cv2, time
app = Flask(__name__)
def gen_frames():
cap = cv2.VideoCapture(0) # 開啟鏡頭
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320) # 設定影像寬度 320
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240) # 設定影像高度 240
while True:
ret, frame = cap.read() # 讀取影像
if not ret:
break
else:
jpg = cv2.imencode('.jpg', frame)[1] # 轉換成 jpg 陣列
mjpeg = jpg.tobytes() # 轉換成傳輸 bytes
# 使用 generator 的方式,每次傳輸特定每個部分
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + mjpeg + b'\r\n')
@app.route('/mjpeg')
def mjpeg():
# 回傳 Multipart Responses
return Response(gen_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/')
def index():
return '''<h1>OXXO.STUDIO 影像串流</h1>
<img src="/mjpeg">'''
if __name__ == '__main__':
app.run("127.0.0.1", port=5000, threaded=True)
因此當網頁開啟後,網頁中所載入的就會自動根據 MJPEG 發送對應的串流,不斷顯示每個部分的影像。
在網頁上點擊右鍵查看網頁原始碼,可以看出顯示串流的 HTML 為一個 img 標籤。
由於使用 Flask 是產生「內網」的網址,如果要透過外部連接查看影像串流,必須使用對外的 IP 或固定網址,也可以串接 nrgok 產生對外網址,詳細參考:使用 ngrok 服務
使用 mjpeg-streamer
除了自己使用 Flask 架設網頁伺服器,也可以使用 mjpeg-streamer 套件架設 MJPEG 的伺服器 ( 常見於樹莓派或一些單晶片裝置使用,詳細參考「mjpeg-streamer,首先輸入指令安裝 opencv-python mjpeg-streamer 套件。
pip install opencv-python mjpeg-streamer --prefer-binary
執行下方程式碼,就會在本機環境建立一個 MJPEG 專屬的伺服器,接著就能使用「http://xxx.xxx.xxx.xxx/mjpeg
」開啟串流圖片,但這個做法只能產生串流影像,如果需要使用自己的網頁樣式呈現串流,則必須使用 Flask 的做法。
import cv2
from mjpeg_streamer import MjpegServer, Stream
cap = cv2.VideoCapture(0)
# 設定串流資訊,mjpeg 為圖片網址 size 尺寸 quality 品質 fps 幀率 ( 每秒幾格 )
stream = Stream("mjpeg", size=(640, 480), quality=50, fps=30)
server = MjpegServer("127.0.0.1", 5000) # 設定伺服器資訊
server.add_stream(stream) # 添加串流
server.start() # 啟動伺服器
while True:
ret, frame = cap.read() # 讀取影像
if not ret:
break
else:
stream.set_frame(frame) # 設定串流內容
小結
使用 Python 建置 MJPEG 的影像串流其實非常簡單,只要熟悉操作原理,就可以自己在家裡建立 IP CAM 攝影機,自己打造自己的監視器囉~
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~