基于Flask的web开发问题笔记

环境:

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));
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值