使用Pyqt5基于yolo目标识别算法实现车辆和行人识别

news2024/11/20 6:35:01

文章目录

  • 一、视频演示
  • 二、实现的功能
    • 2.1、逻辑流程框架
  • 三、Pyqt介绍
    • 3.1、PyQt5软件安装
    • 3.2PyQt5-tools软件安装
  • 四、yolo目标识别算法介绍
    • 4.1、YoloV8环境安装
  • 五、环境搭建
  • 六、运行跑一下
  • 七、代码

一、视频演示

yolo目标识别算法实现车辆识别与行人识别

二、实现的功能

  1. 摄像头雾天画面捕捉与采集:采用雾天检测摄像头实时捕捉当前画面传给处理器。
  2. 对视频和图片信息进行算法识别与处理:将摄像头采集的数据或者本地的数据进行算法处理。
  3. 对车辆和行人标注并输出呈现:算法处理后的信息进行实时标注出车辆和行人并呈现到界面上。
  4. 导出已标注的采样视频功能:将已经标注了的视频可导出,方便反复查看,对交通事故的判定起到很好的记录作用。

2.1、逻辑流程框架

在这里插入图片描述

三、Pyqt介绍

python能做的事很多,使用起来很灵活,包括上位机软件大家熟知的是使用Qt开发,Py也可以的,本项目中用的是PyQt5。
选用PyQt5作为本次系统开发设计的原因有很多,其中是因为它的功能强大并且有着灵活易用的Python库,还提供了丰富的GUI控件、布局管理、事件处理、多线程处理、国际化支持、数据库集成以及与其他库的集成能力。这些功能使得PyQt5成为开发高质量跨平台图形用户界面应用程序的理想选择,所以我选择了使用PyQt5作为本次系统界面和主要逻辑框架的最佳选择。

3.1、PyQt5软件安装

打开CMD或者PowerShell,在命令窗中输入pip install PyQt5。
在这里插入图片描述

3.2PyQt5-tools软件安装

然后安装PyQt5-tools,同样的步骤,在命令窗口输入pip install PyQt5-tools。
在这里插入图片描述

四、yolo目标识别算法介绍

YOLOv8 是于2023年1月10日推出的,截至目前它是计算机视觉领域中用于分类、检测和分割任务的最先进模型。该模型在精度和执行时间方面都优于所有已知模型。YOLOv8是建立在Yolo系列的历史版本基础之上的,在此版本较之前版本在性能上进一步提升和增加了灵活性。YOLOv8具有如下特点,第一对用户友好的 API(命令行 + Python),第二模型更快更准确,第三模型能完成目标检测、实例分割和图像分类任务。YOLOv8是一种无锚(Anchor-Free)模型,这意味着它直接预测对象的中心,而不是通过预测锚框的偏移量来定位对象。相对于使用锚框的传统方法,无锚模型通过减少需要预测的边界框的数量,加速了复杂的推理步骤,如非极大值抑制(NMS)。根据以上特性在雾天的车辆行人识别系统选择此模型是不二选择。

4.1、YoloV8环境安装

YoloV8的安装同样也非常简单,只需要在电脑的管理界面中输入如下三行命令即可。管理界面是通过在Win+R的快捷键,输入cmd,即弹出黑色的对话框,依次输入如下命令即可安装。
详细的yolov8可通过查看官网资料了解

conda create -n yolov8 python= 3.8
activate yolov8
pip install ultralytics

五、环境搭建

在D盘根目录下新建一个文件夹,比如,我创建的文件夹是叫pyqt
在这里插入图片描述
ug文件夹里就是代码,打开此ug文件夹,然后在路径中输入cmd,就会弹出下图中的黑框框
在这里插入图片描述
然后依次在命令行中输入下面的指令,进行安装软件和环境

1、pip list
2、pip3 install torch torchvision torchaudio
如果2下载不成功就用3使用清华的源
3、pip3 install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple
4、Pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

六、运行跑一下

在代码这个目录下的命令行对话框中输入python gui.py
稍等10s左右代码就启动运行了。
在这里插入图片描述
可以选择识别图片或者视频都可以,也可是使用电脑摄像头识别实时捕捉的画面同时支持导出当前识别后的结果。

七、代码

gui.py

import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, 
    QHBoxLayout, QVBoxLayout, QApplication, QLabel,
    QFileDialog, QMessageBox, QRadioButton, QFrame)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import QTimer, Qt
import cv2
import os
from model import PredictModel

class MainGUI(QWidget):
    def __init__(self):
        super().__init__()
        self.windows_title = "基于人工智能的机场车辆行人识别系统"

        self.camera_stat = False   # 摄像头默认关闭
        self.cap = None  # 视频或者摄像头
        self.export_cap = None # 导出的视频
        self.fname = None # 图片或者视频路径

        self.init_ui() # 初始化gui
        self.init_timer() # 初始化定时器
        self.predictor = PredictModel() # 模型预测的类


    def init_ui(self):
        h_layout = QHBoxLayout() # 水平布局


        # 第一列布局,显示窗口  选择图片/视频按钮   打开摄像头按钮
        v1_layout = QVBoxLayout()

        v1_h1_layout = QHBoxLayout() 
        self.display_label = QLabel() # 用于显示图片的label
        self.display_label.setMinimumHeight(300)
        self.display_label.setMinimumWidth(400)
        self.display_label.setStyleSheet("border: 1px dashed")
        v1_h1_layout.addWidget(self.display_label)
        v1_layout.addLayout(v1_h1_layout)

        v1_h2_layout = QHBoxLayout()
        v1_h2_layout.addStretch(1)
        self.image_btn = QPushButton("选择图片/视频")  # 选择图片、视频按钮
        self.image_btn.clicked.connect(self.select_file) # 选择图片视频按钮对应的事件
        v1_h2_layout.addWidget(self.image_btn)
        v1_h2_layout.addStretch(1)
        self.camera_btn = QPushButton("打开/关闭摄像头")  # 打开关闭摄像头按钮
        self.camera_btn.clicked.connect(self.open_camera) # 打开关闭摄像头按钮对应的事件
        v1_h2_layout.addWidget(self.camera_btn)
        v1_h2_layout.addStretch(1)
        v1_layout.addLayout(v1_h2_layout)

        v1_frame = QFrame()
        # v1_frame.setStyleSheet("border: 1px dashed; border-color: (100, 100, 100);")
        v1_frame.setFrameStyle(QFrame.Panel|QFrame.Sunken)
        v1_frame.setLayout(v1_layout)

        # 第二列 显示检测结果
        v2_layout = QVBoxLayout()

        dis_frame = QFrame()
        dis_frame.setFrameStyle(QFrame.Panel|QFrame.Sunken)
        dis_frame.setFixedHeight(50)
        dis_layout = QHBoxLayout()
        self.display_detected_img_btn = QRadioButton("显示检测结果")  # 是否展示检测结果的勾选按钮
        self.display_detected_img_btn.setStyleSheet("border: 1px dashed")
        self.display_detected_img_btn.setChecked(True)
        dis_layout.addWidget(self.display_detected_img_btn)
        dis_frame.setLayout(dis_layout)
        v2_layout.addWidget(dis_frame)

        export_frame = QFrame()
        export_frame.setFixedHeight(120)
        export_frame.setFrameStyle(QFrame.Panel|QFrame.Sunken)
        export_layout = QVBoxLayout()

        self.export_btn = QRadioButton("导出检测结果")   # 是否保存检测结果的选择按钮
        self.export_btn.setStyleSheet("border: 1px dashed")
        self.export_btn.setChecked(True)
        export_layout.addWidget(self.export_btn)

        self.export_path_btn = QPushButton("选择导出路径")  # 如果导出检测结果,选择对应的保存路径
        self.export_path_btn.setChecked(True)
        self.export_path_btn.clicked.connect(self.select_export_path)
        export_layout.addWidget(self.export_path_btn)

        default_export_path = os.path.join(os.getcwd(), 'outputs')
        os.makedirs(default_export_path, exist_ok=True)
        self.export_label = QLabel(default_export_path)
        self.export_label.setFixedHeight(20)
        self.export_label.setStyleSheet("border: 1px dashed; border-color: (100, 100, 100);")
        export_layout.addWidget(self.export_label)
        export_frame.setLayout(export_layout)
        v2_layout.addWidget(export_frame)


        self.info_label = QLabel()  # 展示最终的检测结果
        self.info_label.setStyleSheet("border: 1px dashed")
        v2_layout.addWidget(self.info_label)

        v2_frame = QFrame()
        # v2_frame.setStyleSheet("border: 1px dashed; border-color: (100, 100, 100);")
        v2_frame.setFrameStyle(QFrame.Panel|QFrame.Sunken)
        v2_frame.setLayout(v2_layout)

        h_layout.addWidget(v1_frame)
        h_layout.addWidget(v2_frame)
        self.setLayout(h_layout)
        self.setWindowTitle(self.windows_title)    
        # self.setGeometry(300, 300, 500, 500)
        self.show()

    def select_export_path(self):
        directory = QFileDialog.getExistingDirectory(None, "选择导出文件路径", "./")  # 选择导出的文件路径
        self.export_label.setText(directory)
        return directory

    def select_file(self):
        # 仅允许选择一个文件
        self.fname, _ =QFileDialog.getOpenFileName(self,'打开文件', "./", "Files(*.jpg *.bmp *.png *.jpeg *.mp4 *.avi)") # 选择文件仅允许图片和视频格式
        if self.fname == '':
            return
        if self.fname.endswith(('png', 'bmp', 'jpg', 'jpeg')):
            self.show_single_frame(self.fname)  # 如果是图片,处理图片即可
            self.fname = None     # 清空路径
        else:
            self.cap = cv2.VideoCapture(self.fname)   # 如果是视频,因为视频包含多个帧,逐帧处理,设定一个定时器,每间隔一定的时间就会处理一帧
            if not self.cap.isOpened():
                QMessageBox.information(self, "警告", "视频异常!", QMessageBox.Ok)
                self.cap = None
                return
            self.display_label.setEnabled(True)
            self.timer.start()   # 清空路径放在定时器
            print("beginning!")  # 

    def open_camera(self):
        if self.camera_stat: # 如果摄像头已经开启,那么再次点击就是关闭它
            self.camera_stat = not self.camera_stat
            self.close_camera()
            return
        self.cap = cv2.VideoCapture(0)  # 开启摄像头
        if not self.cap.isOpened():
            QMessageBox.information(self, "警告", "摄像头开启失败!", QMessageBox.Ok)
            self.cap = None
        else:
            self.camera_stat = True
            # 幕布可以播放
            self.display_label.setEnabled(True) # 摄像头开启,开启定时器,逐帧播放
            self.timer.start()
            print("beginning!")
    
    def close_camera(self): 
        # 关闭摄像头,关闭定时器,清空导出路径
        self.cap.release()
        self.cap = None
        self.timer.stop()
        if self.export_cap != None: # 清空导出视频
            self.export_cap.release()
            self.export_cap = None
        self.fname = None

    # 播放视频画面
    def init_timer(self):
        # 初始化定时器,定时器的功能是按照间隔播放摄像头或者视频的内容
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.show_pic)

    # 显示视频图像
    def show_pic(self):
        # 如果是视频或者摄像头,逐帧检测结果
        ret, img = self.cap.read()
        if ret:
            self.show_single_frame(img)

    def show_single_frame(self, img):
        # 检测图片,或者视频和摄像头的一个帧
        image_path = None
        if isinstance(img, str):
            image_path = img
            img = cv2.imread(img) # 如果是图片路径,则读取图片
        ##################################################det#####################################################
        result, det_img, names, cls_info = self.predictor(img) # 对图片或者帧进行预测
        txt = '' # 用于整合显示的检测结果
        print(names, cls_info) # 打印相关信息
        for k in names.keys():
            name = names[k]
            if k in cls_info.keys():
                count = cls_info[k]
                txt += name + ': ' + str(count) + '\n'
            else:
                txt += name + ': ' + '0' + '\n'
        self.info_label.setText(txt) # 将检测结果显示到gui的右下角框内
        if self.display_detected_img_btn.isChecked(): # 如果显示检测结果被选择,则显示检测结果
            img = det_img

        if self.export_btn.isChecked(): # 如果导出按钮被选择
            if image_path is not None: # 检测的是图片
                image_name = os.path.basename(image_path)
                out_path = os.path.join(self.export_label.text(), image_name)
                cv2.imwrite(out_path, det_img)  # 保存检测结果
            else: # 检测的是摄像头或者视频
                if self.export_cap is None: 
                    fourcc = cv2.VideoWriter_fourcc(*'XVID')
                    if self.fname is not None:  # 如果是视频,保存其原有的名字,如果是摄像头,新建名字output.avi
                        video_name = os.path.basename(self.fname)
                        if 'mp4' in video_name:
                            video_name = video_name.replace('mp4', 'avi')
                            print(video_name)
                    else:
                        video_name = 'output.avi'
                    out_path = os.path.join(self.export_label.text(), video_name)
                    width = int(self.cap.get(3))
                    height = int(self.cap.get(4))
                    fps = self.cap.get(cv2.CAP_PROP_FPS)
                    self.export_cap = cv2.VideoWriter(out_path, fourcc, fps, (width, height), True)
                self.export_cap.write(det_img)  # 写入视频
     ##################################################det#####################################################
        cur_frame = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # 视频流的长和宽
        height, width = cur_frame.shape[:2]
        pixmap = QImage(cur_frame, width, height, QImage.Format_RGB888)
        pixmap = QPixmap.fromImage(pixmap)
        # 获取是视频流和label窗口的长宽比值的最大值,适应label窗口播放,不然显示不全
        ratio = max(width / self.display_label.width(), height / self.display_label.height())
        pixmap.setDevicePixelRatio(ratio)
        # 视频流置于label中间部分播放
        self.display_label.setAlignment(Qt.AlignCenter)
        self.display_label.setPixmap(pixmap)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MainGUI()
    sys.exit(app.exec_())

model.py

from PIL import Image
from ultralytics import YOLO
import numpy as np

class PredictModel:
    def __init__(self):
        
        # 加载预训练的YOLOv8n模型
        self.model = YOLO('train/weights/best.pt')
    def __call__(self, img):
        # bgr
        results = self.model(img)
        assert len(results) == 1, "The detected image number must equal 1, but got {}".format(len(results))
        result = results[0]
        names, cls_info = self.post_proccessing(result)
        im_result = result.plot()  # 绘制包含预测结果的BGR numpy数组
        return results, im_result, names, cls_info
    
    def post_proccessing(self, result):
        names = result.names  # 检测的类别名称
        boxes = result.boxes  # 检测的框
        cls = boxes.cls.cpu().numpy().astype('int') # 检测的类别索引
        keys, count = np.unique(cls, return_counts=True) # 检测的每个类别的个数
        cls_info = {}
        # 整合检测的结果
        for key, c in zip(keys, count):
            cls_info[key] = c
        return names, cls_info

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

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

相关文章

【Linux C | 网络编程】进程池大文件传输的实现详解(三)

上一篇实现了进程池的小文件传输,使用自定义的协议,数据长度数据本身,类似小火车的形式,可以很好的解决TCP“粘包”的问题。 【Linux C | 网络编程】进程池小文件传输的实现详解(二) 当文件的内容大小少于…

个人博客搭建——Halo

1 概述 Halo是一个开源的博客系统,有较多的插件支持,用下来感觉还可以 2 搭建流程 2.1 配置系统环境 需要以下系统环境 1、Ubuntu系统 2、Mysql(替换原生数据库) 2.2 下载jar包 这里选择的是jar包部署 下载路径:…

通过nvm在Win7系统中安装v16.17.0及以上版本的nodejs

操作步骤 1.通过nvm安装node - v16.17.0 nvm install 16.17.0若您尚未安装nvm,请参阅:https://blog.csdn.net/weixin_45687201/article/details/135636453 由于我已经安装过了,这里贴图: 2.配置win7环境变量 1.找到node 16.17.…

【AI大模型】Prompt 提示词工程使用详解

目录 一、前言 二、Prompt 提示词工程介绍 2.1 Prompt提示词工程是什么 2.1.1 Prompt 构成要素 2.2 Prompt 提示词工程有什么作用 2.2.1 Prompt 提示词工程使用场景 2.3 为什么要学习Prompt 提示词工程 三、Prompt 提示词工程元素构成与操作实践 3.1 前置准备 3.2 Pro…

“科技创新‘圳’在变革”2025深圳电子展

电子产业作为现代社会的核心驱动力之一,正以前所未有的速度发展。在这样的背景下,深圳作为中国的经济特区和创新高地,又一次迎来了备受瞩目的盛会——2025深圳电子展览会。本次展览会定于2025年4月9日至11日,在深圳会展中心&#…

vue路由跳转时改变路由参数组件不渲染问题【已解决】

效果展示 解决 router路由为了组件复用,防止组件的频繁销毁与创建,在遇到跳转的路由不一致才会进行重新渲染,路径参数变了他是不会管的,只会改变this.$route对象而已 就这个东西/:xxx 我们可以写一个watch监视this.$route对象。…

virtualbox ubuntu扩充磁盘大小

首先在虚拟存储管理里面修改磁盘大小 然后安装gparted sudo gparted 打开管理工具 选中要调整的区域右键选择调整区域大小 拖动上述位置就可以实现扩容。完成后点击应用 然后重启虚拟机即可。

永结无间Ⅱ--大语言模型最终会代替人类吗?

涵盖的主题 当前大语言模型的缺点为何大语言模型 (LLM) 缺乏常识?自主智能的架构相信超级智能的人的说法源于对智力误解的错误推理环境对个人智力有严格限制智力是外在的,存在于文明发展之中无论人工智能变得多么聪明,它都无法扩展递归式自我…

可达2951题 数位拆分

题目: 思路:从二进制的角度,从0到30位每一位来判断求和,开一个新的数组统计第i位是0和1的个数,a[i]放到0~30位的每一位上,然后将a[i]在第位上为0数量乘以2的次方。 代…

编译之舞:C/C++ 与 GCC 的协作曲

文章目录 一、C/C 编译过程的四个阶段1. 编译之舞的台前幕后2. 舞台布景的准备——预处理3. 舞者的基本训练——编译4. 编舞师的细节调整——汇编5. 合奏的和谐统一——链接 二、舞姿的动作细——编译详细模式三、幕后——GCC 的各种选项(Overall Option&#xff09…

Milvus Lite, Milvus Cloud, Standalone, 与 Distributed:组件功能关系深度解析

在大数据时代,高效、灵活的向量搜索解决方案成为了许多企业和研究机构不可或缺的技术支撑。Milvus,作为一款开源的向量数据库,凭借其卓越的性能、可扩展性和易用性,在众多向量搜索引擎中脱颖而出。Milvus 提供了 Lite、Cloud、Standalone、Distributed 四种部署模式,每种模…

55. 跳跃游戏【 力扣(LeetCode) 】

一、题目描述 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 二、测试用…

Python学习笔记44:游戏篇之外星人入侵(五)

前言 上一篇文章中,我们成功的设置好了游戏窗口的背景颜色,并且在窗口底部中间位置将飞船加载出来了。 今天,我们将通过代码让飞船移动。 移动飞船 想要移动飞船,先要明白飞船位置变化的本质是什么。 通过上一篇文章&#xff0…

STM32的GPIO输入输出方式设置示例

1、GPIO口做基本的输入/输出口使用时,输入有上拉输入、下拉输入、浮空输入(既无上拉电阻也无下拉电阻)3种输入方式;输出有开漏输出、推挽输出2种输出方式。 2、示例 (1)示例1:GPIO做输出的设置…

【机器学习】pytorch 常用函数解析

目录 一、基本函数介绍 1.1 nn.Module 类 1.2 nn.Embedding 1.3 nn.LSTM 1.4 nn.Linear 1.5 nn.CrossEntropyLoss 1.6 torch.save 1.7 torch.load 1.8 nn.functional 1.9 nn.functional.softmax 本文主要对 pytorch 中用到的函数进行介绍,本文会不断更新~…

【Redis进阶】主从复制

1. 主从结构引入 在分布式系统中,涉及到一个严重问题:单点问题 即如果某个服务器程序只有一个节点(单台机器提供服务),就会出现以下两个问题: 可用性问题,如果这台机器挂了,意味着…

Github 2024-07-27开源项目日报 Top10

根据Github Trendings的统计,今日(2024-07-27统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量非开发语言项目2C++项目2C项目2TypeScript项目1JavaScript项目1Java项目1Python项目1C#项目1免费编程学习平台:freeCodeCamp.org 创建周期:33…

jQuery入门(一)

一、JQuery介绍 - jQuery 是一个 JavaScript 库。 - 所谓的库,就是一个 JS 文件,里面封装了很多预定义的函数,比如获取元素,执行隐藏、移动等,目的就 是在使用时直接调用,不 需要再重复定义,这…

iPhone 在 App Store 中推出的 PC 模拟器 UTM SE

PC 模拟器是什么?PC 模拟器是一种软件工具,它模拟不同硬件或操作系统环境,使得用户可以在一台 PC 上运行其他平台的应用程序或操作系统。通过 PC 模拟器,用户可以在 Windows 电脑上体验 Android 应用、在 Mac 电脑上运行 Windows …

Python如何获取终端尺寸?

os.get_terminal_size(),无差别获取当前终端长宽,让你为所欲为。 (笔记模板由python脚本于2024年07月27日 08:30:53创建,本篇笔记适合喜欢钻研的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网:https://www.python.org/ Fre…