使用 Python 和 OpenCV 进行实时目标检测的详解

news2024/11/16 11:48:10

        使用到的模型文件我已经上传了,但是不知道能否通过审核,无法通过审核的话,就只能 靠大家自己发挥实力了,^_^

目录

简介

代码介绍

代码拆解讲解

1.首先,让我们导入需要用到的库:

2.然后,设置两个阈值:conf_threshold 和 nms_threshold,以及图片的宽度和高度:

3.接下来,我们加载预训练的 YOLOv3 模型,并加载识别的类名:

4.然后,我们创建一个颜色列表,以在最后的目标检测结果中为不同的类别绘制不同的颜色:

5.下一步,我们定义两个函数 fetch_frame 和 process_frame

6.在主循环中,我们使用 ThreadPoolExecutor 实现了并行处理读取帧和模型推理的操作。

7.退出程序

总体代码

效果展示

​编辑

使用GPU说明

如何操作

1.在读取模型时启用 CUDA:

2.其它代码不需要做太多修改:

总结        


简介

        这段程序是一个Python脚本,它使用了OpenCV库和预训练的YOLOv3模型来实现实时视频流的目标检测。它首先从摄像头捕获视频流,并使用线程池处理每一帧图像。在每一帧中,程序都会检测和识别不同的对象,并用不同的颜色显示结果。使用了非极大值抑制技术删除重复的检测框,并利用了并发处理技术以提高性能。最后,他还显示了每秒处理的帧数(FPS)。我们可以通过按'q'键来结束程序。这个程序展示了一种有效的使用深度学习模型进行实时视觉任务的方法。        


代码介绍

        这段代码是使用OpenCV和Python编写的,主要用于实时视频流处理和目标检测。代码的核心是使用训练好的YOLOv3模型来识别和定位视频帧中的对象。下面是对整个流程的详细解释:

  1. 导入库:首先,导入所需的库,包括cv2(OpenCV),numpy(用于科学计算),time(时间管理),以及concurrent.futures(用于并发执行)。

  2. 初始化参数:设置检测参数,包括置信度阈值(用于过滤掉那些置信度低于阈值的检测结果),非极大值抑制(NMS)阈值(用于去除重复的检测框),以及输入图像的宽和高。

  3. 加载模型和类别:通过使用cv2.dnn.readNet加载预训练的YOLOv3模型,并从coco.names文件中加载可以识别的类名列表。

  4. 颜色列表:为每个可识别的类别创建一个随机颜色列表,这用于在检测到的对象周围绘制彩色的边界框。

  5. 视频捕获:打开摄像头进行视频流的捕获。

  6. 多线程处理:初始化ThreadPoolExecutor以并发执行多个任务。这里定义了两个函数fetch_frameprocess_framefetch_frame用于从视频流中获取一帧图像,而process_frame则用于处理图像并执行目标检测。

  7. 目标检测流程

    • 转换输入帧:将输入帧转换为模型所需要的格式(blob),包括缩放、颜色空间转换等。
    • 执行检测:调用神经网络模型执行前向传播,获取检测结果。
    • 过滤结果:根据置信度阈值和NMS阈值过滤掉一部分检测结果,消除低置信度以及重复的检测框。
    • 绘制边界框和类别标签:在原图上绘制检测到的对象的边界框,并显示类别名称和置信度。
  8. 显示结果:在屏幕上实时显示处理后的视频帧,并计算显示FPS(每秒帧数)。

  9. 程序退出:等待我们按q键退出,并在退出前释放资源,包括摄像头和窗口。

        这段代码的设计利用了异步处理技术(通过ThreadPoolExecutor)来提高处理视频流的效率,使得帧的捕获和处理能够并行执行,从而尽可能提高FPS。

        为什么这样做,主要是我的电脑没有独立GPU,所以,呃,只能动点这中方法了,但是说实话并没有什么实质性的提升,难受了。


代码拆解讲解

        我们将使用预训练的 YOLOv3 模型进行目标检测,并使用 Python 的 concurrent.futures 库来并行处理视频帧的读取和模型推理,以优化程序的执行速度。

        感谢YOLO,虽然现在已经发展到v8了,但是我们这里使用v3还是足够了。

1.首先,让我们导入需要用到的库:

import cv2
import numpy as np
import time
from concurrent.futures import ThreadPoolExecutor

2.然后,设置两个阈值:conf_threshold 和 nms_threshold,以及图片的宽度和高度:

conf_threshold = 0.5
nms_threshold = 0.4
Width = 416
Height = 416

3.接下来,我们加载预训练的 YOLOv3 模型,并加载识别的类名:

net = cv2.dnn.readNet('../needFiles/yolov3.weights', '../needFiles/yolov3.cfg')
with open('../needFiles/coco.names', 'r') as f:
    classes = f.read().strip().split('\n')

4.然后,我们创建一个颜色列表,以在最后的目标检测结果中为不同的类别绘制不同的颜色:

color_list = np.random.uniform(0, 255, size=(len(classes), 3))

5.下一步,我们定义两个函数 fetch_frame 和 process_frame

        fetch_frame 用于从视频对象读取一帧;而 process_frame 则将读取到的帧输入到 YOLOv3 模型中,然后处理获得的输出结果,并在帧上绘制物体检测结果:

def fetch_frame(cap):
    ...
def process_frame(frame):
    ...

6.在主循环中,我们使用 ThreadPoolExecutor 实现了并行处理读取帧和模型推理的操作。

        这样可以使读取下一帧的操作和模型推理操作同时进行,从而显著地加快了处理速度:

executor = ThreadPoolExecutor(max_workers=2)
frame_future = executor.submit(fetch_frame, cap)

while True:
    ...
    ret, frame, height, width, channels = frame_future.result()
    frame_future = executor.submit(fetch_frame, cap)
    processed_frame = executor.submit(process_frame, frame).result()
    ...

7.退出程序

        在这段代码的最后,如果你按下 q 键退出主循环,视频读取对象将会被释放,所有的窗口也将被销毁:

if cv2.waitKey(1) & 0xFF == ord('q'):
    break
...
cap.release()
cv2.destroyAllWindows()

总体代码

# 导入必要的库
import cv2
import numpy as np
import time
from concurrent.futures import ThreadPoolExecutor

# 设置置信度阈值和非极大值抑制(NMS)阈值
conf_threshold = 0.5
nms_threshold = 0.4
Width = 416
Height = 416

# 加载预训练的 YOLOv3 模型
net = cv2.dnn.readNet('../needFiles/yolov3.weights', '../needFiles/yolov3.cfg')

# 加载可识别的类名
with open('../needFiles/coco.names', 'r') as f:
    classes = f.read().strip().split('\n')

# 为不同的类别创建一个颜色列表
color_list = np.random.uniform(0, 255, size=(len(classes), 3))

# 打开摄像头进行视频帧的捕获
cap = cv2.VideoCapture(0)

# 初始化一个ThreadPoolExecutor用于多线程处理
executor = ThreadPoolExecutor(max_workers=2)


# 定义fetch_frame函数,从视频流中获取视频帧
def fetch_frame(cap):
    ret, frame = cap.read()  # 读取一帧图像
    height, width, channels = frame.shape  # 获取图像的尺寸和通道信息
    return ret, frame, height, width, channels


# 定义process_frame函数,处理每帧图像并进行目标检测
def process_frame(frame):
    # 将帧转换为模型的输入格式
    blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
    net.setInput(blob)
    output_layers = net.getUnconnectedOutLayersNames()  # 获取输出层的名字
    layer_outputs = net.forward(output_layers)  # 进行前向传播,获取检测结果

    boxes = []  # 用于存储检测到的边界框
    confidences = []  # 用于存储边界框的置信度
    class_ids = []  # 用于存储边界框的类别ID

    # 循环每个输出层的检测结果
    for output in layer_outputs:
        for detection in output:
            scores = detection[5:]  # 获取类别的得分
            class_id = np.argmax(scores)  # 获取得分最高的类别ID
            confidence = scores[class_id]  # 获取得分最高的置信度

            # 过滤低置信度的检测结果
            if confidence > conf_threshold:
                center_x = int(detection[0] * width)
                center_y = int(detection[1] * height)
                w = int(detection[2] * width)
                h = int(detection[3] * height)

                # 计算边界框的位置和尺寸
                x = int(center_x - w / 2)
                y = int(center_y - h / 2)

                # 将边界框的位置、尺寸、置信度和类别ID添加到列表中
                boxes.append([x, y, w, h])
                confidences.append(float(confidence))
                class_ids.append(class_id)

    # 使用非极大值抑制去除重叠的边界框
    indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)

    # 在原图上绘制边界框和类别标签
    for i in indices.flatten():
        box = boxes[i]
        x = box[0]
        y = box[1]
        w = box[2]
        h = box[3]
        label = str(classes[class_ids[i]])
        color = color_list[class_ids[i]]
        cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)
        cv2.putText(frame, label, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

    return frame


# 在进入循环前,先读取一帧以开始异步处理
frame_future = executor.submit(fetch_frame, cap)

# 主循环
while True:
    start = time.time()  # 记录开始处理的时间点
    # 获取当前帧和相应信息
    ret, frame, height, width, channels = frame_future.result()

    # 异步读取下一帧
    frame_future = executor.submit(fetch_frame, cap)

    # 如果当前帧读取成功,则继续处理
    if ret:
        # 使用线程池异步处理当前帧
        processed_frame = executor.submit(process_frame, frame).result()

        # 计算FPS
        end = time.time()
        fps = 1 / (end - start)
        # 在处理好的帧上显示FPS
        cv2.putText(processed_frame, "FPS: " + str(round(fps, 2)), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0),
                    2)
        # 显示处理好的帧
        cv2.imshow('frame', processed_frame)

        # 如果我们按下 ‘q’ 键,退出循环
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break  # 如果帧没有被成功读取,退出循环

# 释放视频捕获对象和销毁所有OpenCV窗口
cap.release()
cv2.destroyAllWindows()

效果展示

        这个效果还是不错的哈,就是这个硬件性能跟不上,要是有独显就好了。 


使用GPU说明

        当然了,为了在大学时期狠狠的奖励自己四年游戏,很多同学应该都是购买的游戏本,那么恭喜你,你的硬件非常的完美,那么这里你可以看一下。

如何操作

        如果你想利用 GPU 加速你的目标检测代码,主要更改会集中在如何让 OpenCV 利用你的 GPU。不幸的是,OpenCV 的 dnn 模块默认使用 CPU 进行计算。想要使用 GPU,首要条件是你需要有一个支持 CUDA 的 NVIDIA GPU。

        从 OpenCV 4.2 版本开始,dnn 模块添加了对 CUDA 的支持,但实现这一点需要确保你的 OpenCV 是用 CUDA 支持构建的。如果你自己编译 OpenCV,确保在编译时启用了 CUDA 支持。

以下是如何更改你的代码以利用 CUDA 的基本步骤:

1.在读取模型时启用 CUDA:

替换代码中的 readNet 调用,使用 readNetFromDarknet 并添加代码来设置网络的首选后端和目标为 CUDA。

   # 加载预训练的 YOLOv3 模型
   net = cv2.dnn.readNetFromDarknet('../needFiles/yolov3.cfg', '../needFiles/yolov3.weights')
   
   # 启用 CUDA
   net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA)
   net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
2.其它代码不需要做太多修改:

        使用CUDA优化后,主要是模型推理过程(即net.forward()的调用)会更快。数据准备和后处理(例如非极大值抑制)的代码不需要太多修改,因为它们仍然在 CPU 上执行。

        这些改动仅在你已有 OpenCV 版本支持 CUDA,并且你的系统拥有合适的 NVIDIA GPU 时有效。如果你的环境满足这些条件,这样的更改可以显著加快模型推理的速度,尤其是在进行视频流处理时。

        最后,你一定要确定你的环境(包括 NVIDIA 驱动程序和 CUDA Toolkit)被正确设置以支持 GPU 加速。如果你对如何编译支持 CUDA 的 OpenCV 或如何配置你的系统环境有任何疑问,我建议查阅 OpenCV 官方文档和 NVIDIA 的 CUDA 安装指导,因为我真的没有仔细研究过。

总结        

        希望这篇博客对你有所帮助。最后我想说,虽然NVIDIA对我们的学习有帮助,但是我还是想说。

AMDyes!!!

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

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

相关文章

【数据结构-之八大排序(下),冒泡排序,快速排序,挖坑法,归并排序】

🌈个人主页:努力学编程’ ⛅个人推荐:基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 …

【MySQL | 第九篇】重新认识MySQL锁

文章目录 9.重新认识MySQL锁9.1MySQL锁概述9.2锁分类9.2.1锁的粒度9.2.2锁的区间9.2.3锁的性能9.2.4锁的级别 9.3拓展:意向锁9.3.1意向锁概述9.3.2意向锁分类9.3.3意向锁作用(1)意向锁的兼容互斥性(2)例子1&#xff08…

Springboot+vue+小程序+基于微信小程序的在线学习平台

一、项目介绍    基于Spring BootVue小程序的在线学习平台从实际情况出发,结合当前年轻人的学习环境喜好来开发。基于Spring BootVue小程序的在线学习平台在语言上使用Java语言进行开发,在数据库存储方面使用的MySQL数据库,开发工具是IDEA。…

主成分分析在R语言中的简单应用:使用mvstats包

在数据科学领域,主成分分析(PCA)是一种广泛使用的技术,主要用于数据降维和探索性数据分析。PCA可以帮助我们发现数据中的模式,减少数据集的复杂性,同时保持数据中最重要的特征。本文将介绍如何在R语言中使用…

STM32定时器中的编码器接口详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. 编码器接口简介 2. 旋转编码器简介 3. 正交编码器工作模式 4. 基本结构 5. 编码器工作模式示例 6. 代码示例 6.1 Encoder.c 6.2 Encoder.h 6.3 main.c 1. 编码器接口简介 在STM32中&#xf…

Cisco IOS XE Web UI 权限提升漏洞复现(CVE-2023-20198)

0x01 产品简介 Web UI 是一种基于GUI的嵌入式系统管理工具,能够提供系统配置、简化系统部署和可管理性以及增强用户体验。它带有默认映像,因此无需在系统上启用任何内容或安装任何许可证。Web UI 可用于构建配置以及监控系统和排除系统故障,而无需CLI专业知识。 0x02 漏洞…

路由器的构成

一、路由器简介 路由器是互联网中的关键设备: 连接不同的网络路由器是多个输入端口和多个输出端口的专用计算机,其任务是转发分组(转发给下一跳路由器)下一跳路由器也按照这种方法处理分组,直到该分组到达终点为止 …

洛谷 P1377:树的序 ← 笛卡尔树

【题目来源】https://www.luogu.com.cn/problem/P1377【题目描述】 众所周知,二叉查找树的形态和键值的插入顺序密切相关。准确的讲: 1.空树中加入一个键值 k,则变为只有一个结点的二叉查找树,此结点的键值即为 k。 2.在非空树中插…

Vue2基础用法及案例

Vue2基础用法及案例 目录 Vue2基础用法及案例导入响应式布局文本指令v-textv-html 属性指令Vue-set()v-ifv-showv-forv-bindv-model 事件指令v-on函数使用 Class 与 Style 绑定数组绑定对象绑定 案例1:切换图片案例2:过滤查找方法补充 导入 Vue2 cdn &…

如何从 iPhone 恢复已删除或丢失的联系人?

不小心删除了您的 iPhone 联系人?不用担心。我们将向您展示如何从 iPhone或 iPad恢复已删除或丢失的联系人。当您从 iPhone 中删除联系人时,您可能认为无法将其恢复。但事实是,您可以从 iPhone 或 iPad 恢复已删除的联系人,因为它…

04_jvm性能调优_并行收集器介绍

并行收集器(此处也称为吞吐量收集器)是类似于串行收集器的分代收集器。串行和并行收集器之间的主要区别在于并行收集器具有多个线程,用于加速垃圾回收过程。 通过命令行选项-XX:UseParallelGC 可启用并行收集器。默认情况下,使用…

WPF之border标签边框控件、设置弧度、图片

border标签在WPF中承担着边框的角色又称之为边框标签,使用嵌套的方法去给一些标签添加边框,border标签包裹目标标签(border不能有多个子元素)。一般在给标签添加弧度时可以使用border。 常用属性 CornerRadius边框拐角的弧度,当宽高是一样的…

【Mac】Photoshop 2024 for mac最新安装教程

软件介绍 Photoshop 2024是Adobe公司推出的一款图像处理软件,它支持Windows和Mac OS系统。Adobe Photoshop是业界领先的图像编辑和处理软件之一,广泛用于设计、摄影、数字绘画等领域。 Photoshop 2024的功能包括: 1.图像编辑:提…

【16-Ⅰ】Head First Java 学习笔记

HeadFirst Java 本人有C语言基础,通过阅读Java廖雪峰网站,简单速成了java,但对其中一些入门概念有所疏漏,阅读本书以弥补。 第一章 Java入门 第二章 面向对象 第三章 变量 第四章 方法操作实例变量 第五章 程序实战 第六章 Java…

张鸣独到解读:规矩与自信的政治影响

在当今多变的政治舞台上,学者张鸣教授以其犀利而深邃的视角,对规矩与自信提出了新的解读。他的言论不仅引发了公众的广泛关注,也为我们提供了思考社会政治问题的一个新的角度。张教授指出,规矩并非僵化的教条,而应是动…

Linux进程管理与监控

一、相关概念 1、进程的的基本定义 在自身的虚拟地址空间运行的一个独立的程序,从操作系统的角度来看,所有在系统上运行的东西,都可以称为一个进程。 2、进程的分类 系统进程:可以执行内存资源分配和进程切换等管理工作&am…

翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习四

合集 ChatGPT 通过图形化的方式来理解 Transformer 架构 翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习一翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深度学习二翻译: 什么是ChatGPT 通过图形化的方式来理解 Transformer 架构 深…

基于Python的人脸识别系统设计与实现(论文+源码)_kaic

基于Python的人脸识别系统设计与实现 摘 要 随着人工智能的发展,人脸识别系统在我们的生活中越来越被广泛应用。人脸识别系统是指能够从数字图像或视频源中识别人的技术。人脸识别系统可以通过多种方法工作,但是,它们通常是通过将给定图像中的面部特征与…

IDEA基于Maven构建项目

IDEA基于Maven构建项目 一、Maven简介 Apache Maven 是一个软件项目管理和理解工具。基于项目对象模型的概念(POM),Maven 可以从中心信息中管理项目的构建、报告和文档。 Apache Maven 可以用于构建和管理任何基于 Java 的项目。 下载地址…

Axure如何调起浏览器的打印功能

Axure如何调起浏览器的打印功能 答:javascript:window.print(); 不明白的继续往下看 应用场景: 原型设计中,页面上的打印按钮,需要模拟操作演示,需要点击指定的按钮时,唤起浏览器的打印功能&#xff08…