3分钟掌握实时目标检测:使用 OpenCV 和 YOLOv3 的手把手教程

news2024/9/29 9:17:20

实时目标检测:使用 OpenCV 和 YOLOv3

在这篇博客文章中,我们将探讨如何使用 OpenCV 和 YOLOv3 进行实时目标检测。我们将从头到尾演示整个过程,包括加载模型、处理图像和识别对象。

需要的库和工具

首先,我们需要导入以下库:

  • OpenCV: 用于图像处理和计算机视觉的开源库。
  • NumPy: 用于科学计算的库。
pythonCopy codeimport cv2 as cv
import numpy as np

设置摄像头和模型参数

我们首先设置摄像头并定义一些参数,如输入图像的宽高、置信度阈值和非极大值抑制阈值。

pythonCopy codecap = cv.VideoCapture(0) # 打开摄像头
whT = 320 # 定义输入图像的宽高
confThreshold = 0.5 # 置信度阈值
nmsThreshold = 0.2 # 非极大值抑制阈值

加载模型

我们需要加载 YOLOv3 模型,并设置其配置和权重文件的路径。

pythonCopy code# Coco 类别文件路径
classesFile = "coco_classes.txt"
# 用于存储类别名
classNames = []
# 读取类别名
with open(classesFile, 'rt') as f:
    classNames = f.read().rstrip('\n').split('\n')
# YOLOv3 配置文件路径
modelConfiguration = "yolov3.cfg"
# YOLOv3 权重文件路径
modelWeights = "yolov3.weights"
# 读取网络
net = cv.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
# 设置首选后端为 OpenCV
net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
# 设置首选计算目标为 CPU
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)

定义目标检测函数:findObjects

findObjects 函数是代码的核心部分,负责处理网络的输出并在图像上找到并绘制目标对象。以下是函数的详细分析:

pythonCopy codedef findObjects(outputs, img):
    hT, wT, cT = img.shape
    bbox = []
    classIds = []
    confs = []
    for output in outputs:
        for det in output:
            scores = det[5:]
            classId = np.argmax(scores)
            confidence = scores[classId]
            if confidence > confThreshold:
                w, h = int(det[2] * wT), int(det[3] * hT)
                x, y = int((det[0] * wT) - w / 2), int((det[1] * hT) - h / 2)
                bbox.append([x, y, w, h])
                classIds.append(classId)
                confs.append(float(confidence))

    indices = cv.dnn.NMSBoxes(bbox, confs, confThreshold, nmsThreshold)
    for i in indices:
        box = bbox[i]
        x, y, w, h = box[0], box[1], box[2], box[3]
        cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 2)
        cv.putText(img, f'{classNames[classIds[i]].upper()} {int(confs[i] * 100)}%',
                   (x, y - 10), cv.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)

a) 获取图像尺寸

pythonCopy code
hT, wT, cT = img.shape

从输入图像获取高度(hT)、宽度(wT)和通道数(cT)。这些尺寸用于后续的计算。

b) 初始化存储结构

pythonCopy codebbox = []
classIds = []
confs = []
  • bbox 用于存储边界框的坐标和尺寸。
  • classIds 用于存储每个边界框对应的类别 ID。
  • confs 用于存储每个边界框的置信度。

c) 解析网络输出

pythonCopy codefor output in outputs:
    for det in output:
        scores = det[5:]
        classId = np.argmax(scores)
        confidence = scores[classId]
        if confidence > confThreshold:
            # ...

网络的输出包括每个边界框的位置、尺寸、置信度和类别分数。我们遍历每个输出,找到置信度大于阈值的检测结果,并存储相关信息。

d) 计算边界框的位置和尺寸

pythonCopy codew, h = int(det[2] * wT), int(det[3] * hT)
x, y = int((det[0] * wT) - w / 2), int((det[1] * hT) - h / 2)
bbox.append([x, y, w, h])
classIds.append(classId)
confs.append(float(confidence))

我们将网络输出的归一化坐标转换为图像的实际坐标,并存储边界框的位置和尺寸。

e) 应用非极大值抑制

pythonCopy code
indices = cv.dnn.NMSBoxes(bbox, confs, confThreshold, nmsThreshold)

使用非极大值抑制来消除多余的、重叠的框。这确保我们的输出更加精确和干净。

f) 绘制边界框和标签

pythonCopy codefor i in indices:
    box = bbox[i]
    x, y, w, h = box[0], box[1], box[2], box[3]
    cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 2)
    cv.putText(img, f'{classNames[classIds[i]].upper()} {int(confs[i] * 100)}%',
               (x, y - 10), cv.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)

最后,我们遍历非极大值抑制后的索引,对每个检测到的对象,在图像上绘制一个边界框,并添加一个包含类别名和置信度的标签。

主循环:实时目标检测

pythonCopy codewhile True:
    success, img = cap.read()
    blob = cv.dnn.blobFromImage(img, 1 / 255, (whT, whT), [0, 0, 0], 1, crop=False)
    net.setInput(blob)
    layersNames = net.getLayerNames()
    unconnected_out_layers_indices = list(set(net.getUnconnectedOutLayers().flatten()))
    outputNames = [layersNames[i - 1] for i in unconnected_out_layers_indices]
    outputs = net.forward(outputNames)
    findObjects(outputs, img)
    cv.imshow('Image', img)
    cv.waitKey(1)

a) 从摄像头读取图像

pythonCopy code
success, img = cap.read()

使用 OpenCV 的 cap.read() 函数从摄像头读取一帧图像。success 是一个布尔值,表示是否成功读取图像。img 是读取的图像帧。

b) 创建 blob

pythonCopy code
blob = cv.dnn.blobFromImage(img, 1 / 255, (whT, whT), [0, 0, 0], 1, crop=False)

使用 cv.dnn.blobFromImage 函数创建一个 blob,该 blob 是网络输入的适当格式。参数包括:

  • img: 输入图像。
  • 1 / 255: 缩放因子,用于将像素值从 [0, 255] 缩放到 [0, 1]。
  • (whT, whT): 目标尺寸,与网络输入的尺寸相匹配。
  • [0, 0, 0]: 均值减法,用于去均值化。
  • 1: 缩放系数。
  • crop=False: 是否裁剪图像。

c) 设置网络输入

pythonCopy code
net.setInput(blob)

将创建的 blob 设置为网络的输入。

d) 获取网络的输出层名称

pythonCopy codelayersNames = net.getLayerNames()
unconnected_out_layers_indices = list(set(net.getUnconnectedOutLayers().flatten()))
outputNames = [layersNames[i - 1] for i in unconnected_out_layers_indices]

获取网络的层名称,并找出未连接的输出层的索引。这些输出层包含了检测对象的信息。

e) 前向传播

pythonCopy code
outputs = net.forward(outputNames)

通过调用 net.forward 函数并传入输出层名称来执行前向传播。这一步骤将图像通过网络传播,并生成检测结果。

f) 调用目标检测函数

pythonCopy code
findObjects(outputs, img)

将网络输出传递给之前定义的 findObjects 函数,并在图像上找到并标记目标对象。

g) 显示图像

pythonCopy codecv.imshow('Image', img)
cv.waitKey(1)

使用 cv.imshow 显示带有标记的图像。cv.waitKey(1) 是一个暂停命令,等待 1 毫秒的时间。

效果

image-20230821114413358

总结

本项目展示了如何结合深度学习和传统计算机视觉技术来实现实时目标检测。通过 OpenCV 和 YOLOv3,我们能够在普通计算机上实时检测摄像头捕获的图像中的对象。

  • 实用性: 代码可用于许多实际应用,如监控、人机交互、机器人导航等。
  • 灵活性: 通过修改参数和模型,代码可以轻松适应不同的场景和需求。
  • 可访问性: 代码使用了开源和广泛使用的库和模型,使其容易理解和扩展。

整个项目展示了现代计算机视觉项目的典型结构和流程,从图像获取和预处理到深度学习推断和结果可视化。希望这个分析能够帮助你理解如何构建和优化自己的目标检测系统,无论是用于学术研究、工业应用还是个人项目。

完整代码

# 导入 OpenCV 库
import cv2 as cv
# 导入 NumPy 库
import numpy as np

# 打开摄像头
cap = cv.VideoCapture(0)
# 定义输入图像的宽高
whT = 320
# 置信度阈值
confThreshold = 0.5
# 非极大值抑制阈值
nmsThreshold = 0.2

# Coco 类别文件路径
classesFile = "coco_classes.txt"
# 用于存储类别名
classNames = []
# 读取类别名
with open(classesFile, 'rt') as f:
    classNames = f.read().rstrip('\n').split('\n')
# YOLOv3 配置文件路径
modelConfiguration = "yolov3.cfg"
# YOLOv3 权重文件路径
modelWeights = "yolov3.weights"
# 读取网络
net = cv.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
# 设置首选后端为 OpenCV
net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)
# 设置首选计算目标为 CPU
net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)

# 定义函数用于在图像中寻找目标
def findObjects(outputs, img):
    # 获取图像的高、宽和通道数
    hT, wT, cT = img.shape
    # 存储边界框
    bbox = []
    # 存储类别ID
    classIds = []
    # 存储置信度
    confs = []
    # 遍历网络输出
    for output in outputs:
        # 遍历检测结果
        for det in output:
            # 获取分数
            scores = det[5:]
            # 找到最大置信度的类别ID
            classId = np.argmax(scores)
            # 获取置信度
            confidence = scores[classId]
            # 如果置信度大于阈值
            if confidence > confThreshold:
                # 计算边界框的宽和高
                w, h = int(det[2] * wT), int(det[3] * hT)
                # 计算边界框的x和y坐标
                x, y = int((det[0] * wT) - w / 2), int((det[1] * hT) - h / 2)
                # 存储边界框
                bbox.append([x, y, w, h])
                # 存储类别ID
                classIds.append(classId)
                # 存储置信度
                confs.append(float(confidence))

    # 使用非极大值抑制
    indices = cv.dnn.NMSBoxes(bbox, confs, confThreshold, nmsThreshold)
    # 遍历索引
    for i in indices:
        # 获取边界框
        box = bbox[i]
        # 获取坐标和尺寸
        x, y, w, h = box[0], box[1], box[2], box[3]
        # 画矩形
        cv.rectangle(img, (x, y), (x + w, y + h), (255, 0, 255), 2)
        # 添加文本
        cv.putText(img, f'{classNames[classIds[i]].upper()} {int(confs[i] * 100)}%',
                   (x, y - 10), cv.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)

# 循环捕获图像
while True:
    # 读取图像
    success, img = cap.read()
    # 创建 blob
    blob = cv.dnn.blobFromImage(img, 1 / 255, (whT, whT), [0, 0, 0], 1, crop=False)
    # 设置网络输入
    net.setInput(blob)
    # 获取层名称
    layersNames = net.getLayerNames()
    # 获取未连接的输出层索引
    unconnected_out_layers_indices = list(set(net.getUnconnectedOutLayers().flatten()))
    # 获取输出层名称
    outputNames = [layersNames[i - 1] for i in unconnected_out_layers_indices]
    # 前向传播
    outputs = net.forward(outputNames)
    # 在图像中找到对象
    findObjects(outputs, img)
    # 显示图像
    cv.imshow('Image', img)
    # 等待 1 毫秒
    cv.waitKey(1)

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

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

相关文章

Jmeter 接口测试总结

背景介绍 对于 Android 项目来说,使用的是 Java 开发,网络请求接口的数量庞大且复杂,测试人员无法很直观的判断、得出网络请求是否存在问题。另一方面,为了验证请求接口是否能够在大负荷条件下,长时间、稳定、正常的运…

14. 实现业务功能--帖子列表

1. 版块帖子列表 对应版块中显示的帖子列表以发布时间降序排列(desc)不传入版块 Id 返回所有帖子 2. 实现逻辑 用户点击某个版块或首页时,将版块 Id 做为参数向服务器发送请求 服务器接收请求,并获取版块 Id,查询对…

多领域模型效果测试指南

在我最近的写作创作实践中,我尝试了使用不同的模型来测试它们的效果。通过这些测试,我发现每个模型在不同任务上的表现和适用性都有所不同。 首先,对于写作创作领域,我发现生成式模型可以很好地生成创意性的文章和故事。当我使用…

STM32都学什么

一、什么是STM32? 对于STM32,从字面意思上来理解,ST是意法半导体,M是Microelectronics的缩写,其中32表示的是32位,那么整合起来理解就是:STM32就是指的ST公司开发的32位微控制器。在如今的32位控制器中&am…

【二叉树构建与遍历1】先序遍历+中序遍历构建一个二叉树并输出后序遍历 C++实现

思路: 先来一个例子: 先序遍历序列为:FDXEAG 中序遍历序列为:XDEFAG 要根据先序序列和中序序列确定这个二叉树,通用的步骤为: 1.根据先序序列的第一位确定这棵树的根; 2.在中序序列中找到…

LVS之keepalived

1、keepalived 概述 总结:Keepalived 软件就是通过VRRP协议来实现高可用功能。 应用场景:企业应用中,单台服务器承担应用存在单点故障的危险 单点故障一旦发生,企业服务将发生中断,造成极大的危害 VRRP通信原理&…

【CASS精品教程】CAD2016+CASS11.0安装教程(附CASS11.0安装包下载)

文章目录 一、CAD2016_x64安装二、CASS11.0安装1. 安装程序2. 安装补丁3. 安装注册机三、CASS11.0下载地址一、CAD2016_x64安装 CASS11.0.0.8 支持 AutoCAD2010-2023,大家可以根据自己的情况安装对应的版本,本文以CAD2016为例,CAD安装过程略去。 二、CASS11.0安装 点击订…

Pytorch 手写数字识别-MINIST 数据集训练

CNN 前期文章我们分享了tensorflow 的手写数字识别的训练以及识别过程,有网友私信是否写一下pytorch训练识别过程,本期文章我们来分享一下pytorch的手写数字训练人工智能TensorFlow(十六)MNIST手写数字识别 说到图片识别就不得不提卷积神经网络,我们会在后期详细介绍,或者…

docker启动容器失败:STATUS:‘ Exited ‘

先查看正在运行的容器 # 查看正在运行的容器 docker ps # 查看所有的docker容器 docker ps -a 这个时候如果显示的是up状态,那就是启动成功了。 状态为exited,所以没有启动成功。 解决问题 1、移除镜像 先把镜像移除掉 //移除一个镜像(出现问题可以移…

一篇文章看懂前端性能优化(2023详解)

性能优化这个词我们经常会在前端的工作或面试中遇到,这个东西说难好像也并不怎么难,毕竟谁都能说上几点。但是如果你想在工作上遇到各种场景的性能瓶颈时都有直击本质的性能方案,或者在面试时让面试官眼前一亮,那就不能只拘泥于『…

nodejs+vue+elementui大学生就业管理系统hch86

本学生就业管理系统以vue作为框架,b/s模式以及MySql作为后台运行的数据库, 本系统主要包括首页,个人中心,辅导员管理,学生管理,企业管理,工作类型管理,企业招聘管理,投简…

TOWE机房电源线的用料成分及导体材质大揭秘

在IDC数据机房中,各种制式的电源转换线是一个连接设备端与供电端的重要配件产品。平常我们在各大电商平台搜索电源转换线产品,会发现同一种电源线,有卖几十块钱的,也有十块钱不到的。同一产品出现较大价差的现象,最根本…

信息监理工程师-----监理内容

文章目录 信息监理工程师的监理内容1 四控1.1 质量控制1.2 进度控制1.3 投资控制1.4 变更控制 2 三管2.1 信息管理2.2 合同管理2.3 信息安全管理 3 一协调3.1 协调 信息监理工程师的监理内容 监理活动的主要内容被概括为"四控,三管,一协调". 1 四控 四控&#xff…

ES:一次分片设计问题导致的故障

### 现象: 1. 单节点CPU持续高 2.写入骤降 3.线程池队列积压,但没有reject 4.使用方没有记录日志 ### 排查 1.ES监控 只能看到相应的结果指标,无法反应出原因。 2.ES日志:大量日志打印相关异常(routate等调用栈&a…

docker安装Oracle11gR2

文章目录 目录 文章目录 前言 一、前期准备 二、具体配置 2.1 配置oracle容器 2.2 配置navicat连接 总结 前言 使用docker模拟oracle环境 一、前期准备 安装好docker #拉取镜像 docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g #启动 docker run -…

书单背景图怎么设置,怎么把书单转成视频?

书单是一种记录阅读内容的方式,它可以让我们更好地跟踪我们的阅读进度并分享我们的阅读心得。有时候你想要将自己的书单转化为视频格式来与更多人分享,但你不知道如何做到这一点。在本文中,我将向你介绍如何设置书单背景图并将书单转成视频。…

操作系统-笔记-第二章-锁

目录 二、第二章——【锁】 1、互斥锁​编辑 2、信号量机制 (1)信号量机制——整形信号量 (2)信号量机制——记录信号量 (3)总结(重点——记录信号量) 3、信号量机制——实现…

数仓分类及基本概念

【数仓建设系列之二】数仓分类及基本概念 随着移动互联网的快速发展,数据的生产也成几何式的增长,传统意义上的数据库已经无法满足日益增长的需求,建设一个好的数仓,不仅可以为企业的决策和发展带来具有价值的指导意义&#xff0c…

Python自动化测试代理程序可用性

在网络爬虫和数据采集过程中,代理服务器扮演着重要的角色。然而,代理服务器的可用性经常会受到影响,给爬虫工作带来一定的挑战。本文将介绍如何使用Python自动化测试代理程序的可用性,为您提供具备实际操作价值的解决方案。让我们…

同为科技(TOWE)65W快充插排插线板,快人一步,乐享生活

在现代生活中,手机、平板、笔记本电脑等电子设备已成为人们生活中不可或缺的工具。然而,诸多电子产品在充电方面也出现了许多问题,比如充电过程慢、插口不够用、充电时温度过高等。随着随着技术的更新迭代,满足高功率、多接口且多…