1. 程式人生 > 實用技巧 >樹莓派(4-6)網頁伺服器 flask為背景的 websocket網頁雙向通訊+視訊流顯示

樹莓派(4-6)網頁伺服器 flask為背景的 websocket網頁雙向通訊+視訊流顯示

功能

1 完成了傳輸視訊

2完成了網頁端前後相互控制

百度網盤

連結:https://pan.baidu.com/s/1YZ6bY86LVoNMDr6PSPCGnw
提取碼:pxj0

原理講解

讀取程式碼 flasksever.py

#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import time


from flask import *
from flask_socketio import *

from camera import *
video=VideoCamera()


import time
from threading import Lock
import datetime,random #匯入時間和隨機數模組
import cv2

    

app = Flask(
    __name__,
    template_folder='.',  # 表示在當前目錄 (myproject/A/) 尋找模板檔案
    static_folder='',     # 空 表示為當前目錄 (myproject/A/) 開通虛擬資源入口
    static_url_path='',
)

app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, async_mode=None)

thread = None
thread_lock = Lock()


import os
pathnow=os.getcwd()
pathnow=pathnow.replace('\\','/')
#print(pathnow) #獲取當前工作目錄路徑
#print (os.path.abspath('mainPage0.html'))

HTML_PATH=pathnow




 
@app.route('/')
def index():
    return render_template('websocket.html', async_mode=socketio.async_mode)



#傳輸視訊
def gen(camera):
    coutrec=1
    while True:
        coutrec=coutrec+1
        socketio.emit('server_recmsg2_frame',
                      {'data': str(coutrec)},
                      namespace='/test')
        
        frame = video.get_frame()  
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')
        

# 伺服器每傳送一次請求,video_feed被呼叫一次
@app.route('/video_feed')
def video_feed():
    return Response(gen(video), mimetype='multipart/x-mixed-replace; boundary=frame')



# 後臺執行緒 產生資料,即刻推送至前端
def background_thread():
    count = 0
    while True:
        #socketio.sleep(1)
        count += 1
        # 獲取系統時間(只取分:秒)
        t = time.strftime('%M:%S', time.localtime())
       
       
        socketio.emit('server_recmsg1_backthread',
                      {'data': [str(t), str(count+1)], 'count': count},
                      namespace='/test')
        time.sleep(1)

    



@socketio.on('connect', namespace='/test')
def test_connect():
    global thread
    with thread_lock:
        if thread is None:
            thread = socketio.start_background_task(target=background_thread)

            



#注意如何send()和emit()分別用於無名和命名事件。

@socketio.on('client_recmsg', namespace='/test')
def test_message(message):
    #emit('message', {'data': message['data']},broadcast=True)  #函式內傳送
    print(message['data'])
    



    
if __name__ == '__main__':
    socketio.run(app,'0.0.0.0',8081,debug=False)
   
    

  

camera.py

# camera.py
import cv2
 
class VideoCamera(object):
    def __init__(self):
        # Using OpenCV to capture from device 0. If you have trouble capturing
        # from a webcam, comment the line below out and use a video file
        # instead.
        self.video = cv2.VideoCapture(0)
        # If you decide to use video.mp4, you must have this file in the folder
        # as the main.py.
        # self.video = cv2.VideoCapture('video.mp4')
 
    def __del__(self):
        self.video.release()
 
    def get_frame(self):
        success, image = self.video.read()
        # We are using Motion JPEG, but OpenCV defaults to capture raw images,
        # so we must encode it into JPEG in order to correctly display the
        # video stream.
        ret, jpeg = cv2.imencode('.jpg', image)
        # 對於 python2.7 或者低版本的 numpy 請使用 jpeg.tostring()
        return jpeg.tobytes()

  

網頁websocket.html

中間引用了websocket的js庫,我下載到了本地,可以去網上找到對應地址,百度網盤也有這個庫的離線版本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>系統監控走勢圖</title>
    
    <script type="text/javascript" src="jquery.min.js"></script>
    <script type="text/javascript" src="socket.io.min.js"></script>
    <script type="text/javascript" src="//cdn.bootcss.com/jquery/3.1.1/jquery.min.js"></script>
    <script type="text/javascript" src="//cdn.bootcss.com/socket.io/1.5.1/socket.io.min.js"></script>
</head>
 
<body>
  
        <div>
            <button id="state1" >傳送按鈕</button> <br><br>
            <a> 已傳送訊息:</a>
            <a id="sendnews"></a><br>

            <a>1伺服器伴隨執行緒發來的訊息:</a>
            <a id="receivenews1"></a><br>

            <a>2伺服器視訊流主動發來的訊息:</a>
            <a id="receivenews"></a><br>
        </div>
        
        <br>
        <a>連線狀態:</a>
        <div id="statemsg">正在連線...</div>
        <br>


    <script type="text/javascript">

 
    // 建立socket連線,等待伺服器“推送”資料,用回撥函式更新圖表
    $(document).ready(function() {

        namespace = '/test';
        var socket = io.connect(location.protocol + '//' + document.domain + ':' + location.port + namespace);

        socket.on('connect', function(){
              console.log('connected')
              statemsg.innerHTML ='connected'
            });

        //接受話題2 F12列印訊息  開啟視訊 主動推送訊息
        socket.on('server_recmsg2_frame', function(res) {

           console.log(res)
           document.getElementById("receivenews").innerHTML=res.data;
        });


        //接受話題1 F12列印訊息 背後程序伴隨伺服器開啟,不停接收後臺資料
        socket.on('server_recmsg1_backthread', function(res) {
          
           console.log(res.data[0]);//後臺列印
           document.getElementById("receivenews1").innerHTML=res.data[0];//接收訊息顯示<a>
           //statemsg.innerHTML = res.count;//文字狀態顯示<div>
          
         });

        //設定點選事件
        document.getElementById("state1").onclick = function(e){
        //給伺服器傳送訊息
        socket.emit('client_recmsg',{'data': 1, 'count': 1});
        document.getElementById("sendnews").innerHTML="給後臺發資料 'data': 1, 'count': 1"
        }


 
    });
 
    </script>

   <a>視訊流</a><br>
  <img src="{{ url_for('video_feed') }}" height="300" width="300" >
    



</body>
</html>