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

马肤

温馨提示:这篇文章已超过446天没有更新,请注意相关的内容是否还可用!

摘要:,,本文介绍了使用Python和OpenCV进行实时目标检测的方法。通过结合OpenCV库的功能和Python编程语言的灵活性,可以实现高效的目标检测系统。文章详细解释了目标检测的流程,包括图像预处理、特征提取、模型训练以及实时检测等步骤。还讨论了目标检测中的关键技术和挑战,如目标定位、分类和识别等。本文旨在为开发者提供实时目标检测的实用指南和技术参考。

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

目录

简介

代码介绍

代码拆解讲解

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

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

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

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

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

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

7.退出程序

总体代码

效果展示

​编辑

使用GPU说明

如何操作

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

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

总结        


使用 Python 和 OpenCV 进行实时目标检测的详解,Python与OpenCV实时目标检测详解 第1张

简介

        这段程序是一个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_frame和process_frame。fetch_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()

效果展示

使用 Python 和 OpenCV 进行实时目标检测的详解,Python与OpenCV实时目标检测详解 第2张

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


使用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!!!

使用 Python 和 OpenCV 进行实时目标检测的详解,Python与OpenCV实时目标检测详解 第3张


0
收藏0
文章版权声明:除非注明,否则均为VPS857原创文章,转载或复制请以超链接形式并注明出处。

相关阅读

  • 【研发日记】Matlab/Simulink自动生成代码(二)——五种选择结构实现方法,Matlab/Simulink自动生成代码的五种选择结构实现方法(二),Matlab/Simulink自动生成代码的五种选择结构实现方法详解(二)
  • 超级好用的C++实用库之跨平台实用方法,跨平台实用方法的C++实用库超好用指南,C++跨平台实用库使用指南,超好用实用方法集合,C++跨平台实用库超好用指南,方法与技巧集合
  • 【动态规划】斐波那契数列模型(C++),斐波那契数列模型(C++实现与动态规划解析),斐波那契数列模型解析与C++实现(动态规划)
  • 【C++】,string类底层的模拟实现,C++中string类的模拟底层实现探究
  • uniapp 小程序实现微信授权登录(前端和后端),Uniapp小程序实现微信授权登录全流程(前端后端全攻略),Uniapp小程序微信授权登录全流程攻略,前端后端全指南
  • Vue脚手架的安装(保姆级教程),Vue脚手架保姆级安装教程,Vue脚手架保姆级安装指南,Vue脚手架保姆级安装指南,从零开始教你如何安装Vue脚手架
  • 如何在树莓派 Raspberry Pi中本地部署一个web站点并实现无公网IP远程访问,树莓派上本地部署Web站点及无公网IP远程访问指南,树莓派部署Web站点及无公网IP远程访问指南,本地部署与远程访问实践,树莓派部署Web站点及无公网IP远程访问实践指南,树莓派部署Web站点及无公网IP远程访问实践指南,本地部署与远程访问详解,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南,树莓派部署Web站点及无公网IP远程访问实践详解,本地部署与远程访问指南。
  • vue2技术栈实现AI问答机器人功能(流式与非流式两种接口方法),Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法探究,Vue2技术栈实现AI问答机器人功能,流式与非流式接口方法详解
  • 发表评论

    快捷回复:表情:
    评论列表 (暂无评论,0人围观)

    还没有评论,来说两句吧...

    目录[+]

    取消
    微信二维码
    微信二维码
    支付宝二维码