【OpenCV DNN】Flask 视频监控目标检测教程 10

news2024/11/20 20:24:14

欢迎关注『OpenCV DNN @ Youcans』系列,持续更新中

【OpenCV DNN】Flask 视频监控目标检测教程 10

    • 3.10 OpenCV DNN+Flask实时监控目标检测
      • 1、加载MobileNet SSD模型
      • 2、导入分类名称文件
      • 3、处理视频帧进行目标检测
      • 4、新建一个Flask项目
      • 5、Python 程序文件
      • 6、视频流的网页模板
      • 7、Flask 视频监控目标检测程序运行


本系列从零开始,详细讲解使用 Flask 框架构建 OpenCV DNN 模型的 Web 应用程序。

在上节的基础上,本节介绍使用OpenCV DNN对实时视频进行目标检测。DNN目标检测的基本步骤也是加载图像、模型设置和模型推理。


3.10 OpenCV DNN+Flask实时监控目标检测

在上节的基础上,本节介绍使用OpenCV DNN对实时视频进行目标检测。DNN目标检测的基本步骤也是加载图像、模型设置和模型推理。

我们使用TensorFlow深度学习框架在MS COCO数据集上训练的MobileNet SSD(单次检测器)模型。与其他目标检测模型相比,SSD 模型通常更快。此外,MobileNet 主干网还降低了计算密集度。因此,对于使用OpenCV DNN进行目标检测,MobileNet是一个很好的模型。

MS COCO数据集(https://cocodataset.org/)是当前基于深度学习的对象检测模型的基准数据集。MS COCO包括80类日常物品,从人到汽车,再到牙刷。可以使用文本文件加载 MS COCO 数据集中的所有标签。


1、加载MobileNet SSD模型

在VideoStream类初始化程序中,使用readNet()函数加载MobileNet SSD模型。model为预训练权重文件的路径,即冻结计算图(frozen graph)的路径。Config为模型配置文件的路径,即protobuf文本文件的路径。Framework为加载模型的框架名称,本例中是TensorFlow。

# 加载 DNN 模型:MobileNet SSD 模型
model = cv2.dnn.readNet(model='./models/frozen_inference_graph.pb',
          config='./models/ssd_mobilenet_v2_coco.pbtxt',
          framework='TensorFlow')

2、导入分类名称文件

然后导入读取分类名称文件object_detection_classes_coco.txt,该文件将每个类别名称存储在列表class_names中,用新行分隔每个类别。例如:

[‘person’, ‘bicycle’, ‘car’, ‘motorcycle’, ‘airplane’, ‘bus’, ‘train’, ‘truck’, ‘boat’, ‘traffic light’, … ‘book’, ‘clock’, ‘vase’, ‘scissors’, ‘teddy bear’, ‘hair drier’, ‘toothbrush’, ‘’]

为每个类别随机设置不同颜色COLORS,用于使用指定颜色为每个类别绘制边界框,以便在图像中通过边界框的颜色来区分不同类别。元组COLORS包括3个整数值,表示颜色分量。

# 读取 COCO 类别名称
with open('object_detection_classes_coco.txt', 'r') as f:
   class_names = f.read().split('\n')
  
# 为每个类别随机设置不同的颜色
COLORS = np.random.uniform(0, 255, size=(len(class_names), 3))

3、处理视频帧进行目标检测

本例程在主线程中处理视频帧进行目标检测,使用一个线程update_frame()实时获取新的视频帧。

在主线程中的生成器函数gen_frames()逐帧获取图片,使用MobileNet SSD(单次检测器)模型进行目标检测,将图像编码后返回给客户端。客户端浏览器收到视频流以后,在img标签定义的图片中逐帧显示,从而实现视频播放。

生成器函数gen_frames() 处理视频帧进行目标检测的步骤如下:
(1)由视频帧 frame 创建blob对象;
(2)使用MobileNet SSD模型,进行目标检测;
(3)对检测到的目标进行筛选,确定目标类别和边界框;
(4)在视频帧上绘制边界框,并标注类别名称;
(5)将图像编码后返回给客户端。

例程如下。

# 创建 blob
blob = cv2.dnn.blobFromImage(image=image, size=(300, 300), mean=(104, 117, 123), swapRB=True)

# 基于 DNN 模型的目标检测
start = time.time()
self.model.setInput(blob)  # 模型输入图像
output = self.model.forward()  # 模型前向推理
end = time.time()
fps = 1 / (end - start)  # 计算帧处理速率 FPS

# 目标检测结果的后处理
for detection in output[0, 0, :, :]:
    # 提取检测的置信度
    confidence = detection[2]
    # 当置信度高于阈值时才绘制边界框
    if confidence > 0.5:
        class_id = detection[1]  # 获取类别的id
        if class_id >= 90:  class_id = 89  # 防止类别id超出范围
        class_name = self.class_names[int(class_id) - 1]  # 将id映射为类别标签
        color = self.COLORS[int(class_id)]  # 该类别的颜色设置
        # color = (0, 255, 0)
        # 获取矩形边界框的参数 (x, y, w, h)
        x_box = int(detection[3] * w_img)
        y_box = int(detection[4] * h_img)
        w_box = int(detection[5] * w_img)
        h_box = int(detection[6] * h_img)
        # 在图像上绘制检测目标的矩形边界框
        cv2.rectangle(image, (x_box, y_box), (w_box, h_box), color, thickness=2)
        # 在图像上添加类别名称
        cv2.putText(image, class_name, (x_box, y_box - 5), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
        # 在图像上添加 FPS 文本
        # cv2.putText(image, f"{fps:.2f} FPS", (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

4、新建一个Flask项目

新建一个Flask项目cvFlask10,本项目的框架与cvFlask09相同。
cvFlask10项目的文件树如下。

---文件名\
    |---models\
    |    |--- object_detection_classes_coco.txt
    |    |--- ssd_mobilenet_v2_coco.pbtxt
    |    |--- ssd_mobilenet_v2_coco_frozen.pb
    |---templates\
    |    |---index4.html
    |    |---index5.html
|--- cvFlask10.py
|--- vedio_01.mp4

5、Python 程序文件

任务逻辑由Python程序文件cvFlask10.py实现,完整代码如下。

# cvFlask10.py
# OpenCV+Flask 图像处理例程 10
# OpenCV+Flask+threading+MobileNet SSD
# OpenCV 实时读取摄像头,MobileNetSSD 模型目标检测,浏览器实时播放监控视频
# Copyright 2023 Youcans, XUPT
# Crated:2023-5-18

# coding:utf-8

from flask import Flask, Response, request, render_template
import threading
import time
import numpy as np
import cv2

app = Flask(__name__)  # 实例化 Flask 对象

# 定义视频流类
class VideoStream:
    def __init__(self, source):  # 传入视频源
        # 创建视频捕获对象,调用笔记本摄像头
        # cam = cv2.VideoCapture(0, cv2.CAP_DSHOW)  # 修改 API 设置为视频输入 DirectShow
        self.video_cap = cv2.VideoCapture(0)  # 创建视频读取对象
        self.success, self.frame = self.video_cap.read()  # 读取视频帧
        threading.Thread(target=self.update_frame, args=()).start()

        # 加载 DNN 模型:MobileNet SSD V2 模型
        self.model = cv2.dnn.readNet(model="./models/ssd_mobilenet_v2_coco_frozen.pb",
                                config="./models/ssd_mobilenet_v2_coco.pbtxt",
                                framework='TensorFlow')
        # 读取 COCO 类别名称文件
        with open("./models/object_detection_classes_coco.txt", 'r') as f:
            self.class_names = f.read().split('\n')
        # 为每个类别随机设置不同的颜色
        self.COLORS = np.random.uniform(0, 255, size=(len(self.class_names), 3))

    def __del__(self):
        self.video_cap.release()  # 释放视频流

    def update_frame(self):
        while True:
            self.success, self.frame = self.video_cap.read()

    def get_frame(self):
        image = self.frame
        h_img, w_img, _ = image.shape

        # 创建 blob
        blob = cv2.dnn.blobFromImage(image=image, size=(300, 300), mean=(104, 117, 123), swapRB=True)

        # 基于 DNN 模型的目标检测
        start = time.time()
        self.model.setInput(blob)  # 模型输入图像
        output = self.model.forward()  # 模型前向推理
        end = time.time()
        fps = 1 / (end - start)  # 计算帧处理速率 FPS

        # 目标检测结果的后处理
        for detection in output[0, 0, :, :]:
            # 提取检测的置信度
            confidence = detection[2]
            # 当置信度高于阈值时才绘制边界框
            if confidence > 0.5:
                class_id = detection[1]  # 获取类别的id
                if class_id >= 90:  class_id = 89  # 防止类别id超出范围
                class_name = self.class_names[int(class_id)-1]  # 将id映射为类别标签
                color = self.COLORS[int(class_id)]  # 该类别的颜色设置
                # color = (0, 255, 0)
                # 获取矩形边界框的参数 (x, y, w, h)
                x_box = int(detection[3] * w_img)
                y_box = int(detection[4] * h_img)
                w_box = int(detection[5] * w_img)
                h_box = int(detection[6] * h_img)
                # 在图像上绘制检测目标的矩形边界框
                cv2.rectangle(image, (x_box,y_box), (w_box,h_box), color, thickness=2)
                # 在图像上添加类别名称
                cv2.putText(image, class_name, (x_box,y_box-5), cv2.FONT_HERSHEY_SIMPLEX, 1, color, 2)
                # 在图像上添加 FPS 文本
                # cv2.putText(image, f"{fps:.2f} FPS", (20, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)

        ret, buffer = cv2.imencode('.jpg', image)  # 编码为 jpg 格式
        frame_byte = buffer.tobytes()  # 转换为 bytes 类型
        return frame_byte

# 生成视频流的帧
def gen_frames(video_source):
    video_stream = VideoStream(video_source)  # 从视频文件获取视频流
    while True:
        frame = video_stream.get_frame()  # 获取视频帧
        if frame is None:
            # video_stream.__del__()  # 释放视频流
            break
        yield (b'--frame\r\n' b'Content-Type: image/jpeg\r\n\r\n'
               + frame + b'\r\n')  # 生成视频流的帧


@app.route('/video_feed')
def video_feed():
    video_source = request.args.get('video_source', 'camera')  # 从网页获取视频源

    # 通过将一帧帧的图像返回,就达到了看视频的目的。multipart/x-mixed-replace是单次的http请求-响应模式,如果网络中断,会导致视频流异常终止,必须重新连接才能恢复
    return Response(gen_frames(video_source), mimetype='multipart/x-mixed-replace; boundary=frame')

@app.route('/')
def index_camera():  # 实时视频监控
    # <img src="{{ url_for('video_feed', video_source='camera') }}">
    return render_template('index4.html')

@app.route('/vidfile')
def index_vidfile():  # 播放视频文件
    # <img src="{{ url_for('video_feed', video_source='vedio_01.mp4') }}">
    return render_template('index5.html')

if __name__ == '__main__':
    # 启动一个本地开发服务器,激活该网页
    print("URL: http://127.0.0.1:5000")
    app.run(host='0.0.0.0', port=5000, debug=True, threaded=True)  # 绑定 IP 地址和端口号



6、视频流的网页模板

视频流的网页模板index4.html和index5.html位于templates文件夹,内容与cvFlask09项目完全相同。

网页index4.html位于templates文件夹,具体内容如下。

<!DOCTYPE html>
<html>
  <head>
    <title>Video Streaming Demonstration</title>
  </head>
  <body>
    <h2  align="center">OpenCV+Flask 例程:实时视频监控</h2>
    <div style="text-align:center; padding-top:inherit">
      <img src="{{ url_for('video_feed', video_source='camera') }}" width="600"; height="360">
    </div>
  </body>
</html>

网页index5.html位于templates文件夹,具体内容如下。

<!DOCTYPE html>
<html>
  <head>
    <title>Video Streaming Demonstration</title>
  </head>
  <body>
    <h2  align="center">OpenCV+Flask 例程:播放视频文件</h2>
    <div style="text-align:center; padding-top:inherit">
      <img src="{{ url_for('video_feed', video_source='vedio_01.mp4') }}" width="600"; height="360">
    </div>
  </body>
</html>

7、Flask 视频监控目标检测程序运行

进入cvFlask10项目的根目录,运行程序cvFlask10.py,启动流媒体服务器。

在局域网内设备(包括移动手机)的浏览器打开http://192.168.3.249:5000就可以播放实时视频监控画面。

在这里插入图片描述

进一步地,我们添加两个控制按钮“Start”和“Stop”,用来控制开始和停止播放视频流。
在 Flask 应用中添加控制按钮需要修改前端和后端代码。前端需要添加按钮以及发送请求的 JavaScript 代码,后端则需要添加处理这些请求的路由。
我们在前端添加 “start” 和 “stop” 按钮,这两个按钮在被点击时会发送请求到 “/start” 和 “/stop” 路由。


【本节完】


版权声明:
欢迎关注『OpenCV DNN @ Youcans』系列
youcans@xupt 原创作品,转载必须标注原文链接:
【OpenCV DNN】Flask 视频监控目标检测教程 10
(https://blog.csdn.net/youcans/article/details/131365824)
Copyright 2023 youcans, XUPT
Crated:2023-06-24


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680517.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

linux系统addr ip以及ifconfig查询不到ip地址解决方法,没有ens33

先看使用情况 网上一堆垃圾博文解决方案都是你抄我我抄你&#xff0c;一点用没有&#xff0c;都说使用 vi /etc/sysconfig/network-scripts/ifcfg-ens33 来更改配置ONBOOT为yes&#xff0c;改个屁&#xff0c;给你们看看我目前的配置&#xff0c;劳资本身就是yes&#xff0c;还…

Elasticsearch 基本使用(二)简单查询 嵌套查询

查询数据 简单查询按id查询单条记录查询所有数据设置排序filter 过滤查询数组内的值查询 嵌套查询查询一个外层字段 内的嵌套字段查询多个字段&#xff0c;其中有嵌套字段 简单查询 按id查询单条记录 GET bank/_doc/1查询所有数据 默认只查询10条记录 GET bank/_search {&q…

Linux任务调度、磁盘分区、挂载

一、任务调度介绍 任务调度是指系统在某个时间执行的特定的命令或程序 任务调度分为两类&#xff1a; 1.系统工作&#xff1a;有些重要的工作必须周而复始的执行&#xff0c;比如病毒扫描 2&#xff0c;个别用户工作&#xff1a;个别用户可能希望执行某些程序&#xff0c;比如…

canvas自定义绘制顺序解决遮挡问题

canvas自定义绘制顺序解决遮挡问题 1. 问题场景2. 解决思路3. 实现代码 1. 问题场景 使用canvas绘制进行要素叠加时&#xff0c;往往会出现不是按照先画的在下面&#xff0c;后画的在最上面这样的顺序进行叠加显示。原因就是由于图片大小不同导致绘制或加载的时间不一样&#…

合宙Air724UG Cat.1模块硬件设计指南--LCD专用SPI接口

概述 Air724UG支持一路LCD专用SPI接口&#xff0c;用于驱动SPI LCD屏幕&#xff0c;不能作为通用SPI使用 特性&#xff1a; 最大支持320240分辨率&#xff0c;30帧 内置图像处理单元GOUDA 支持格式&#xff1a; YUV4 : 2 : 0 ;YUV4 : 2 : 2;RGB565; ARGB8888 目前只支持4线8bi…

MySQL - 第8节 - MySQL复合查询

1.基本查询回顾 准备测试表&#xff1a; • 下面给出三张表&#xff0c;分别是员工表&#xff08;emp&#xff09;、部门表&#xff08;dept&#xff09;和工资等级表&#xff08;salgrade&#xff09;。 • 后续所要进行的查询操作都将以这三张表作为数据源&#xff0c;包括基…

【论文笔记】BEIT:BERT PRE-TRAINING OF IMAGE TRANSFORMERS

GitHub 1.介绍 1.1 挑战 视觉转换器的输入单元&#xff0c;即图像补丁&#xff0c;没有预先存在的词汇。预测遮罩面片的原始像素往往会在预训练短程依赖性和高频细节上浪费建模能力 1.2 回顾一下Bert的基本架构和流程 输入编码&#xff1a;通过tokenizer将输入的文本中的每…

gmpy2

简介 gmpy2是一个Python扩展模块&#xff0c;是对GMP的封装&#xff0c;它的前身是gmpy。 GMP&#xff08;即GNU高精度算术运算库&#xff09;&#xff0c;它是一个开源的高精度运算库&#xff0c;其中不但有普通的整数、实数、浮点数的高精度运算&#xff0c;还有随机数生成&a…

【promptulate专栏】使用ChatGPT和XMind快速构建思维导图

本文节选自笔者博客&#xff1a;https://www.blog.zeeland.cn/archives/ao302950h3j &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#…

Go语言基础:标识符、关键字、变量、常量、iota

一、标识符 在编程语言中标识符就是程序员定义的具有特殊意义的词&#xff0c;比如变量名、常量名、函数名等等。 Go语言中标识符由字母数字和_(下划线&#xff09;组成&#xff0c;并且只能以字母和_开头。 二、关键字 关键字是指编程语言中预先定义好的具有特殊含义的标识符…

ThreadPoolExecutor的应用和源码分析

前面描述的线程池的创建方式大都是Executors类中创建出来&#xff0c;基于ThreadPoolExecutor去new出来实现的。 我们为什么要自定义线程池 在线程池ThreadPoolExecutor中提供了7个参数&#xff0c;都作为非常核心的属性&#xff0c;在线程池去执行任务的时候&#xff0c;每个…

【Docker】容器化和虚拟化基础

Docker发展史 Jail(监狱)时代 1979 年 贝尔实验室发明 chroot chroot的设计原理是&#xff1a;把一个进程的文件系统隔离起来。 ​ chroot 系统调用可以将进程及其子进程的根目录更改为文件系统中的新位置。隔离以后&#xff0c;该进程无法访问到外面的文件&#xff0c;因此这…

管理类联考——逻辑——知识篇——论证推理——二、加强——haimian

考点分析 加强 年度 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023题量213325356 主要问法 以下哪项如果为真&#xff0c;最能加强上述结论的说服力?以下哪项如果为真&#xff0c;最能支持题干的论证? 解题思路 阅读问题&#xff0c;确定是否为加强题型&…

进程参数编程

问题 execve(...) 的参数分别是什么&#xff1f;有什么意义&#xff1f; 第一个参数是程序路径&#xff0c;第二个参数是进程参数&#xff0c;第三个参数是环境变量 再论 execve(...) main 函数 (默认进程入口) int main(int argc, char* argv[]) argc - 命令行参数个数argv…

java——jdbc编程

文章目录 JDBC的概念JDBC的常用APIJDBC示例代码PreparedStatementCallableStatement JDBC&#xff08;Java Database Connectivity&#xff09;是Java的一种数据库访问标准&#xff0c;它提供了一套API&#xff0c;使得我们可以通过Java程序来访问和操作各种关系型数据库。 下面…

从零开始手搓一个STM32与机智云的小项目——GPIO模拟时序控制外设2

文章目录 前言模块简介硬件介绍硬件连接通信时序DHT11的数据帧格式信号时序1. 起始信号2.应答信号(响应信号)3.接收数据0与14.获取数据5结束信号 输入输出切换实际效果 总结 前言 在上一篇中介绍了&#xff0c;使用GPIO模拟WS2812B的控制时序来实现对RGB灯的控制&#xff0c;本…

【开源与项目实战:开源实战】84 | 开源实战四(上):剖析Spring框架中蕴含的经典设计思想或原则

在 Java 世界里&#xff0c;Spring 框架已经几乎成为项目开发的必备框架。作为如此优秀和受欢迎的开源项目&#xff0c;它是我们源码阅读的首选材料之一&#xff0c;不管是设计思想&#xff0c;还是代码实现&#xff0c;都有很多值得我们学习的地方。接下来&#xff0c;我们就详…

Nginx服务的主配置文件 nginx.conf

目录 前言 一、Nginx.con位置 二、Nginx.com相关内容 三、Nginx.conf中配置块和指令 1、I/O时间配置 2、HTTP 配置 日志格式设定 总结 前言 Nginx 的主配置文件是 nginx.conf&#xff0c;它通常位于 Nginx 的安装目录下的 conf 文件夹中。主配置文件 nginx.conf 是 Ngin…

Rust语言从入门到入坑——(6)Rust组织管理

文章目录 0 引入1、组织概念1. 1、箱1. 2、包1. 3、模块 2、组织中权限2.1 权限2.2 模块引用2.2 Use 关键词 3、总结 0 引入 任何一门编程语言如果不能组织代码都是难以深入的&#xff0c;几乎没有一个软件产品是由一个源文件编译而成的。本教程到目前为止所有的程序都是在一个…

java——内部类和异常处理

文章目录 内部类成员内部类局部内部类匿名内部类静态内部类 异常处理异常捕获与处理多重异常捕获和处理抛出异常 内部类 Java内部类&#xff08;Inner Class&#xff09;是嵌套在其他类中的类&#xff0c;它可以访问外部类的成员变量和方法&#xff0c;同时也可以被外部类访问…