實用
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>
