环境:
python==3.8.9
numpy==1.21.1
Flask==2.0.1
1. 相对路径报错
问题:
项目上传Git,clone 下来之后启动报错。
使用相对路径获取文件夹报错,FileNotFoundError;
使用os.cwd()打印出来是桌面的路径。
解决:
需要点击 Edit Configurations, 修改 Working dictionary 为 启动文件 所在的文件夹。
2. python 传参数给 html
问题:
使用 render_template 将参数传递给html, 如何在html中调用?
render_template('*.html', param='param')
解决:
使用 {{ param }} 的形式,在html中使用,如果是 script 标签中,
可以加单引号 '{{ param }}' 的形式获取到字符串。
3. POST请求参数获取
问题:
从 flask 导入 request ,使用 request.args.get('key') 获取不到参数。
解决:
这是由于 request.args 是 GET 请求使用的,
POST 请求需要使用 request.form 。
如果是上传文件,则需要使用 request.files.get('file') 来获取到文件。
随后直接 file.save(path) 保存文件,或者进行其他形式的存储即可。
4. global关键字使用?
在函数外定义了一个变量 x, 在函数内重新赋值,警告
shadows name “x” from outer scope
x = 1
def change():
x = 2
应该使用global关键字,如下:
x = 1
def change():
global x
x = 2
理解:
Python变量的作用域一共有4种,分别是:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
所以函数内直接 x = 2,其实创建了一个局部变量,并没有影响外部的 x,所以会报警告,外部的 x 也没有更新
不过,还是要尽量避免使用 global
补充:最后经过优化,使用了 类class,每个实例有自己的变量
5. 怎么展示视频流?
需要使用 yield + Response
在html中添加img标签,src为后端接口
<img src="video_read" width="300px" style="margin: 20px 0;">
后端接口如下:
# __init__.py
import app.video_read as vr
@app.route('/video_read') # 这个地址返回视频流响应
def video_read_1():
print('返回视频流响应')
return Response(vr.read_pic(),
mimetype='multipart/x-mixed-replace; boundary=frame')
# video_read.py
import os
import cv2
import imghdr
from threading import Thread
import time
import app.config as config
import hashlib
from app.predict import predict
is_start = True
video_url = ""
jpg_name = ""
def load_video(url):
"""
加载视频源
:param url:
:return:
"""
print("加载视频源 ----")
global video_url
video_url = url
global jpg_name
jpg_name = hashlib.md5(video_url.encode()).hexdigest() + ".jpg"
Thread(target=get_snapshot, args=(url,)).start()
def end_video(url):
"""
断开视频源
:param url:
:return:
"""
video_capture.stop()
def get_snapshot(url):
global video_capture
video_capture = WebCamVideoStream(src=url).start()
if video_capture.stream.isOpened():
while True:
if video_capture.stopped:
continue
success, frame = video_capture.read() # video_capture读取视频流
if success:
jpg_path = os.path.join(config.SNAPSHOT_PATH, jpg_name)
# print("输出图片::::" + jpg_path)
cv2.imwrite(jpg_path, frame)
# time.sleep(config.PIC_INTERVAL) # 每隔 n 秒输出图片
else:
# 需要重连视频源 TODO
print("获取帧失败,结束....")
break
print("关闭视频源 -----")
video_capture.stream.release()
video_capture.stop()
class WebCamVideoStream:
def __init__(self, src):
print("多线程,高效读视频")
# initialize the video camera stream and read the first frame
# from the stream
self.url = src
self.stream = cv2.VideoCapture(src)
# self.stream.set(cv2.CAP_PROP_POS_AVI_RATIO, 1) # 定处理的帧百分比 视频文件相对位置 0开始 1结束
# self.stream.set(cv2.CAP_PROP_FPS, 1) # 帧率 帧/秒
if self.stream:
print("视频源是否打开:" + src + ' ' + str(self.stream.isOpened()))
if self.stream.isOpened():
(self.grabbed, self.frame) = self.stream.read()
else:
print("视频源打开失败:" + src)
# initialize the variable used to indicate if the thread should
# be stopped
self.stopped = False
def start(self):
# start the thread to read frames from the video stream
Thread(target=self.update, args=()).start()
return self
def update(self):
# keep looping infinitely until the thread is stopped
while True:
# if the thread indicator variable is set, stop the thread
if self.stopped:
return
# otherwise, read the next frame from the stream
if self.stream.isOpened():
(self.grabbed, self.frame) = self.stream.read()
def read(self):
# return the frame most recently read
return self.grabbed, self.frame
def stop(self):
# indicate that the thread should be stopped
self.stopped = True
self.stream.release()
def read_pic():
while True:
try:
if video_capture.stream.isOpened():
success, frame = video_capture.read() # video_capture读取视频流
if success:
image = frame
else:
print("获取帧失败,结束....")
except NameError:
# 代表未执行连接视频源操作
image = cv2.imread(config.NOT_CONNECT_PIC)
ret, jpeg = cv2.imencode('.jpg', image)
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + jpeg.tobytes() + b'\r\n\r\n')
6. 怎么让接口持续返回结果?
应该还是使用 yield + Response,还没搞明白
7. 读取RTMP推流,报错 4057 URL 非法
问题:
我是使用读取视频流的帧,持续返回给img标签,但是报错 4057 URL 非法 URL参数缺失或校验不通过, 打断点发现,request.args.get(“url”) 获取到的只有 & 之前的内容
比如:
<!-- 未连接时使用 static 中的图片 -->
<img id="video" src="{{ url_for('static', filename='image/notConnect.jpg') }}" />
$('#video').attr('src', "read_video?url=" + url);
url = request.args.get("url")
# 获取到的是 rtmp://localhost/live?a=1
解决:
需要把url的值编码,如下:
$('#video').attr('src', "read_video?url=" + encodeURIComponent(url));