實用
https://blog.csdn.net/u012675539/article/details/53306335
第一篇 講解原理
https://blog.miguelgrinberg.com/post/video-streaming-with-flask
第二篇 加入多線程可以直接用
https://github.com/xitu/gold-miner/blob/master/TODO1/flask-video-streaming-revisited.md
https://zhuanlan.zhihu.com/p/54292646
鏈接:https://pan.baidu.com/s/16iyO_XR_JhhHn184RVH6Hw
提取碼:6dq6
http://shumeipai.nxez.com/2018/07/17/raspberry-pi-cam-pan-tilt-control-over-local-inter.html
樹莓派+Flask實現視頻流媒體WEB服務器
http://shumeipai.nxez.com/2018/07/03/video-streaming-web-server-with-flask.html
1最簡單的模式
opencv
單線程
# main.py from flask import Flask, render_template, Response from camera import VideoCamera app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') def gen(camera): while True: frame = camera.get_frame() 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)
# 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()
<html> <head> <title>Video Streaming Demonstration</title> </head> <body> <h1>Video Streaming Demonstration</h1> <img src="{{ url_for('video_feed') }}"> </body> </html>
簡單幾步實現RTMP直播
主服務器
#!/usr/bin/env python2 # -*- coding: utf-8 -*- dianliang_v=100 import os from configparser import ConfigParser import datetime #存一個新數據 def writeconfig(time,dianliang): conf_path = "config.ini" #配置文件路徑 config = ConfigParser() config.read(conf_path, encoding="utf-8") #獲取當前長度 secs=config.sections() print(len(secs)) config.add_section(str(len(secs)+1)) config.set(str(len(secs)+1), '時間:', time) config.set(str(len(secs)+1), '電量:', dianliang) #保存修改 with open(conf_path, "w") as fw: config.write(fw) import time import RPi.GPIO as GPIO GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) pinA1=12 # 左電機1 pinA2=16 # 左電機 2 pinB1=20 # 右電機 1 pinB2=21 # 右電機 2 pin_alram=22 # 報警器 GPIO.setup(pinA1, GPIO.OUT) #設置腳為輸出模式 GPIO.setup(pinA2, GPIO.OUT) #設置腳為輸出模式 GPIO.setup(pinB1, GPIO.OUT) #設置腳為輸出模式 GPIO.setup(pinB2, GPIO.OUT) #設置腳為輸出模式 GPIO.setup(pin_alram, GPIO.OUT) #設置腳為輸出模式 go_time_intever=0.2 # 運動步長(秒) 通過改時間來改每一步的運動距離 def go_ahead(): print ("go_ahead") GPIO.output(pinA1, GPIO.HIGH) # A往前轉 GPIO.output(pinA2, GPIO.LOW) #滅 GPIO.output(pinB1, GPIO.HIGH) # B往前轉 GPIO.output(pinB2, GPIO.LOW) #滅 time.sleep( go_time_intever ) #延時 秒 def go_back(): print ("go_ahead") GPIO.output(pinA1, GPIO.LOW) # A往前轉 GPIO.output(pinA2, GPIO.HIGH) #滅 GPIO.output(pinB1, GPIO.LOW) # B往前轉 GPIO.output(pinB2, GPIO.HIGH) #滅 time.sleep( go_time_intever ) #延時 秒 def stop(): print ("stop") GPIO.output(pinA1, GPIO.LOW) # A停止 GPIO.output(pinA2, GPIO.LOW) #滅 GPIO.output(pinB1, GPIO.LOW) # B停止 GPIO.output(pinB2, GPIO.LOW) #滅 time.sleep( go_time_intever ) #延時 秒 def tuen_left(): print ("tuen_left") GPIO.output(pinA1, GPIO.LOW) # A往后轉 GPIO.output(pinA2, GPIO.HIGH) #滅 GPIO.output(pinB1, GPIO.HIGH) #B往前轉 GPIO.output(pinB2, GPIO.LOW) #滅 time.sleep( go_time_intever ) #延時 秒 def turn_right(): print ("turn_right") GPIO.output(pinA1, GPIO.HIGH) #A往前轉 GPIO.output(pinA2, GPIO.LOW) #滅 GPIO.output(pinB1, GPIO.LOW) #B往后轉 GPIO.output(pinB2, GPIO.HIGH) #滅 time.sleep( go_time_intever ) #延時 秒 #from flask import Flask, render_template, Response,request,redirect,url_for from flask import Flask, render_template, Response,request,redirect,url_for from camera import VideoCamera import cv2 video=VideoCamera() app = Flask(__name__) @app.route('/') def index(): return render_template('dengku.html') @app.route('/use') def use(): return render_template('index1.html') @app.route('/login', methods = ["GET","POST"]) def login(): name = request.args.get("username") password = request.args.get("userpwd") print('待驗證賬戶:'+name+" 待驗證密碼:"+password) if name== 'admin' and password=='admin': #return redirect(url_for('use')) return '登錄成功' else: return '登錄失敗' @app.route('/move', methods = ["GET","POST"]) def move(): fx = request.args.get("movefx") #print('運動方向:'+fx) if fx=='qian': print('前行') go_ahead() fx='前行' elif fx=='hou': print('后退') go_back() fx='后退' elif fx=='zuo': print('左轉') tuen_left() fx='左轉' elif fx=='you': print('右轉') turn_right() fx='右轉' elif fx=='stop': print('停止') stop() fx='停止' else: pass return fx # 各種事情處理 @app.route('/do', methods = ["GET","POST"]) def do(): ting = request.args.get("dowhat") #拍照 if ting=="paizhao": img = video.get_img() cv2.namedWindow('image',0) cv2.imshow('image',img) cv2.waitKey(10) cv2.imwrite('save/image.jpg', img) ting='拍照成功' print(ting) elif ting=="close_alram": ting='警報關閉' GPIO.output(pin_alram, GPIO.LOW) #低電平 print(ting) pass elif ting=="open_alram": ting='警報打開' GPIO.output(pin_alram, GPIO.HIGH) #高電平 print(ting) pass elif ting=="show_etc": ting='當前電量:' global dianliang_v dianliang_v=dianliang_v-1 nowTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') writeconfig(str(nowTime),str(dianliang_v)) ting=ting+str(dianliang_v)+"--"+str(nowTime) print(ting) pass return ting # 2添加 電量 # 3添加 config保存 def gen(camera): while True: frame = camera.get_frame() 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(video), mimetype='multipart/x-mixed-replace; boundary=frame') if __name__ == '__main__': app.run(host='0.0.0.0',port='8080')
相機類
# 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_img(self): success, image = self.video.read() return image 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()
網頁
<html> <head> <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" /> <title>視頻流測試</title> </head> <body> <h1>視頻流演示</h1> <script type="text/javascript"> function GETmethod(msg) { var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { document.getElementById("demo").innerHTML = this.responseText; alert("登錄成功!") if(this.responseText=="登錄成功"){ window.location.href="use"} } }; xhttp.open("GET", msg, true); xhttp.send(); } //button 按鈕,結合onclick事件,驗證和提交表單 function checkForm(){ //判斷用戶名是否為空 if(document.form1.username.value==""){ window.alert("用戶名不能為空"); }else{ //方法一 使用form對象的submit()方法,實現參數提交。整體刷新網頁,無法獲取返回值做邏輯控制 //document.form1.submit(); //方法二 使用xjax提交,局部刷新網頁 可以獲取返回值 msg= 'login?'+'username='+document.form1.username.value +'&userpwd='+document.form1.userpwd.value GETmethod(msg) } } </script> <form name="form1" method="get" action="login"> 用戶名:<input type="text" name="username" /> 密碼:<input type="password" name="userpwd" /> <input type="button" value="登錄驗證" onclick="checkForm()" /> </form> <div id="demo"> <h1>狀態提示...</h2> </div> </body> </html>