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