使用YOLOv8和PySimpleGUI构建目标计数GUI

简介: 使用YOLOv8和PySimpleGUI构建目标计数GUI

标检测是在图片或视频中定位物体的过程。其中一个著名的目标检测框架是YOLO(You Only Look Once)。在某些情况下,我们不仅需要定位图片或视频中的物体,还需要了解每个物体的运动,就像在这篇文章中,我们想要计数通过某些位置的物体。这就是我们需要不仅仅是检测的地方,我们需要称为目标跟踪的东西的地方。


外,大多数情况下,我们通常只是通过执行脚本或命令行中的代码来使用它,如果我们可以将我们的模型部署为GUI或应用程序,以便用户更轻松地使用它,那将更好。在这篇文章中,将分享如何使用框架YOLOv8和PySimpleGUI构建一个目标计数GUI。


什么是YOLOv8?


YOLOv8,即You Only Look Once version 8,是由UItralytics开发的图像处理框架,YOLOv8可以执行目标检测和跟踪、实例分割、图像分类和姿态估计任务。

YOLOv8的用法

YOLOv8与先前版本的性能比较

使用YOLOv8进行目标跟踪

有很多方法可以使用YOLOv8进行目标跟踪。我喜欢Python脚本方法,因为我可以有更多的控制权,使用此方法需要执行以下几个步骤,您还可以从Ultralytics的文档中查看此链接。


1. 创建虚拟环境


python -m venv yologui

2. 激活虚拟环境


yologui\Scripts\activate

3. 安装YOLOv8的依赖项


pip install -r https://raw.githubusercontent.com/ultralytics/ultralytics/main/requirements.txt

4. 安装YOLOv8


pip install ultralytics

5. 创建一个yolo脚本


# https://docs.ultralytics.com/modes/track/#python-examples
import cv2
from ultralytics import YOLO
# Load the YOLOv8 model
model = YOLO('yolov8n.pt')
# Open the camera
cap = cv2.VideoCapture(0)
# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()
    if success:
        # Run YOLOv8 tracking on the frame, persisting tracks between frames
        results = model.track(frame, persist=True)
        # Visualize the results on the frame
        annotated_frame = results[0].plot()
        # Display the annotated frame
        cv2.imshow("YOLOv8 Tracking", annotated_frame)
        # Break the loop if 'q' is pressed
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    else:
        # Break the loop if the end of the video is reached
        break
# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()


执行脚本,您应该可以得到由YOLOv8进行的目标跟踪:


python yolo.py

这是结果,当满意时按“Q”退出。

目标追踪结果


您可以看到我们的脚本可以记住左侧图片中的泰迪熊与右侧图片中的泰迪熊是相同的。实际上,他是一只狗....


添加目标跟踪的计数逻辑

目标跟踪为我们提供了比目标检测更多的选项,其中之一是我们可以使用它来计算进入或离开框架中某个区域或线的独特目标的数量。

跟踪物体A和B的运动


要计算通过我们的线左右经过的物体数量,我们需要从我们的目标跟踪脚本中提取目标的id和位置。Ultralytics的模型已经为我们提供了该属性,通过使用以下命令来处理跟踪结果。


# Using Model
results= model.track(frame, persist=True)
# Extrack result
result = results[0].cpu().boxes
detect_id = result.id.tolist() if result.id != None else []
detect_xyxy = result.xyxy.tolist() if result.xyxy != None else []
frame_counting_buffer = dict(zip(detect_id, detect_xyxy))


因此,我们可以获取每个目标的位置,接下来是进行一些计算,以了解目标是从右到左还是从左到右经过。在这种情况下,我只关注目标的中心和X轴。以下是在X轴上进行目标计数的完整脚本。


# https://docs.ultralytics.com/modes/track/#python-examples
import cv2
from ultralytics import YOLO
# Load the YOLOv8 model
model = YOLO('yolov8n.pt')
# Counting config
line_position = 50
text_size = 30
text_x_position = 50
text_y_position = 0
# Open the camera
cap = cv2.VideoCapture(0)
# Get Camera Parameter
width  = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
# Counting prep
x_line= line_position*width/100
pt1 = (int(x_line), 0)
pt2 = (int(x_line), int(height))
counting_buffer = {}
counting_result = {'left-to-right' : 0, 'right-to-left' : 0}
# Loop through the video frames
while cap.isOpened():
    # Read a frame from the video
    success, frame = cap.read()
    if success:
        # Run YOLOv8 tracking on the frame, persisting tracks between frames
        results = model.track(frame, persist=True, verbose=False)
        # Visualize the results on the frame
        annotated_frame = results[0].plot()
        # Get Data for counting
        result = results[0].cpu().boxes
        detect_id = result.id.tolist() if result.id != None else []
        detect_xyxy = result.xyxy.tolist() if result.xyxy != None else []
        frame_counting_buffer = dict(zip(detect_id, detect_xyxy))
        # Process
        for i in frame_counting_buffer :
            # Prep count buffer
            counting_buffer[i] = counting_buffer.get(i,[])
            if len(counting_buffer[i]) >= 2 : counting_buffer[i] = counting_buffer[i][-1:]
            # Append avg x axis to buffer
            avg_x = (frame_counting_buffer[i][0] + frame_counting_buffer[i][2])/2
            counting_buffer[i].append(avg_x)
            # Count logic
            if len(counting_buffer[i]) >= 2 : 
                if (counting_buffer[i][0] > x_line) & (counting_buffer[i][1] < x_line) :
                    counting_result['right-to-left'] += 1
                elif (counting_buffer[i][0] < x_line) & (counting_buffer[i][1] > x_line) :
                    counting_result['left-to-right'] += 1
        # Create Line
        cv2.line(annotated_frame, pt1= pt1, pt2= pt2 , color= (0,0,255), thickness= 2) 
        # Put Counting to picture
        text_position = text_y_position
        for i in counting_result : 
            text_position += text_size
            info_text = f"{i} : {counting_result[i]}"
            annotated_frame = cv2.putText(annotated_frame
                                          , info_text
                                          , (int(width*text_x_position/100), text_position)
                                          , cv2.FONT_HERSHEY_SIMPLEX
                                          , 1, (0,0,255), 1, cv2.LINE_AA)
        # Display the annotated frame
        cv2.imshow("YOLOv8 Tracking", annotated_frame)
        # Break the loop if 'q' is pressed
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
    else:
        # Break the loop if the end of the video is reached
        break
# Release the video capture object and close the display window
cap.release()
cv2.destroyAllWindows()


然后,我们将得到一个如图所示的目标计数脚本,当满意时按Q。


什么是PySimpleGUI?

PySimpleGUI是一个用于制作GUI的Python库,具有跨平台性且非常简单易用。

从PySimpleGUI的页面获取图片


GUI的框架

创建GUI时,有一些比编码更重要的东西,即设计阶段。我们在编码之前应该有一些草图设计。在这种情况下,我画了一个目标计数GUI的初步设计,就像这张图片一样。                                                                     GUI初步设计


设计阶段后,接下来就是编码:

1. 安装PySimpleGUI。


pip install pysimplegui

2. 创建一个GUI脚本


# https://www.pysimplegui.org/en/latest/#jump-start
import PySimpleGUI as sg
# Create Layouy of the GUI
layout = [  
            [sg.Text('GUI Object Counting with Yolo V8')],
            [sg.Text('Enter Model Name', size= (15)), sg.InputText(key='model_name')],
            [sg.Text('X-line for Counting', size= (15)), sg.InputText(key= 'line_position')],
            [sg.Button('Run'), sg.Button('Stop'), sg.Button('Close')],
            [sg.Text('PICTURE')],
            [sg.Text('Left-to-Right', size= (15), key='out1'), sg.Text("0", key='out1-v')],
            [sg.Text('Right-to-Left', size= (15), key='out2'), sg.Text("0", key='out2-v')]
            ]
# Create the Window
window = sg.Window('GUIYoloV8-Counting', layout)
# Event Loop to process "events"
while True:
    event, values = window.read()
    # When press Run
    if event == 'Run' : 
        print(values)
    # When close window or press Close
    if event in (sg.WIN_CLOSED, 'Close'): break
# Close window
window.close()


正如您所见,PySimpleGUI的脚本非常简单。之后,我们所要做的就是运行此GUI脚本。


python gui.py


之后,您应该会得到一个像图中这样的简单GUI,尝试玩耍并在满意时关闭。


合并

我们有了目标计数和GUI框架之后,是时候将它们合并到一起了。我们可以将两个脚本合并成一个名为main.py的新脚本,如下所示:


# https://www.pysimplegui.org/en/latest/#jump-start
import PySimpleGUI as sg
import cv2
# https://docs.ultralytics.com/modes/track/#python-examples
from ultralytics import YOLO
# Create Layouy of the GUI
layout = [  
            [sg.Text('GUI Object Counting with Yolo V8')],
            [sg.Text('Enter Model Name', size= (15)), sg.InputText(key='model_name')],
            [sg.Text('X-line for Counting', size= (15)), sg.InputText(key= 'line_position')],
            [sg.Button('Run'), sg.Button('Stop'), sg.Button('Close')],
            [sg.Image(filename='', key='image')],
            [sg.Text('Right-to-Left', size= (15), key='out1'), sg.Text("0", key='right-to-left')],
            [sg.Text('Left-to-Right', size= (15), key='out2'), sg.Text("0", key='left-to-right')]
            ]
# Create the Window
window = sg.Window('GUIYoloV8-Counting', layout)
run_model, verbose = False, False
# Event Loop to process "events"
while True:
    event, values = window.read(timeout=0)
    # When press Run
    if event == 'Run' : 
        # Load the YOLOv8 model
        model = YOLO(values['model_name'])
        # Counting config
        line_position = 50
        text_size = 30
        text_x_position = 50
        text_y_position = 0
        # Open the camera
        cap = cv2.VideoCapture(0)
        # Get Camera Parameter
        width  = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
        height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
        # Counting prep
        x_line= line_position*width/100
        pt1 = (int(x_line), 0)
        pt2 = (int(x_line), int(height))
        counting_buffer = {}
        counting_result = {'left-to-right' : 0, 'right-to-left' : 0}
        # Run Signal
        run_model = True
    # When close window or press Close
    elif event in ('Stop', sg.WIN_CLOSED, 'Close'):
        if run_model : 
            run_model = False # Stop running
            cap.release() # Release video
            if event != sg.WIN_CLOSED : window['image'].update(filename='') # Destroy picture
        # When close window or press Close
        if event in (sg.WIN_CLOSED, 'Close'): break
    # Run Model
    if run_model : 
        # Read a frame from the video
        success, frame = cap.read()
        if success:
            # Run YOLOv8 tracking on the frame, persisting tracks between frames
            results = model.track(frame
                                  , persist=True
                                  , verbose=False
                                  )
            # Visualize the results on the frame
            annotated_frame = results[0].plot()
            # Get Data for counting
            result = results[0].cpu().boxes
            detect_id = result.id.tolist() if result.id != None else []
            detect_xyxy = result.xyxy.tolist() if result.xyxy != None else []
            frame_counting_buffer = dict(zip(detect_id, detect_xyxy))
            # Process
            for i in frame_counting_buffer :
                # Prep count buffer
                counting_buffer[i] = counting_buffer.get(i,[])
                if len(counting_buffer[i]) >= 2 : counting_buffer[i] = counting_buffer[i][-1:]
                # Append avg x axis to buffer
                avg_x = (frame_counting_buffer[i][0] + frame_counting_buffer[i][2])/2
                counting_buffer[i].append(avg_x)
                # Count logic
                if len(counting_buffer[i]) >= 2 : 
                    if (counting_buffer[i][0] > x_line) & (counting_buffer[i][1] < x_line) :
                        counting_result['right-to-left'] += 1
                    elif (counting_buffer[i][0] < x_line) & (counting_buffer[i][1] > x_line) :
                        counting_result['left-to-right'] += 1
            # Create Line
            cv2.line(annotated_frame, pt1= pt1, pt2= pt2 , color= (0,0,255), thickness= 2) 
            # Put Counting to picture
            text_position = text_y_position
            for i in counting_result : 
                text_position += text_size
                info_text = f"{i} : {counting_result[i]}"
                annotated_frame = cv2.putText(  annotated_frame
                                            , info_text
                                            , (int(width*text_x_position/100)
                                            , text_position)
                                            , cv2.FONT_HERSHEY_SIMPLEX
                                            , 1
                                            , (0,0,255)
                                            , 1
                                            , cv2.LINE_AA)
            # Show Image
            imgbytes = cv2.imencode('.png', annotated_frame)[1].tobytes()
            window['image'].update(data=imgbytes)
            window['right-to-left'].update(str(counting_result['right-to-left']))
            window['left-to-right'].update(str(counting_result['left-to-right']))
        else: 
            # Break the loop if not read
            cap.release()
            run_model = False
# Close window
window.close()


然后,我们可以运行主脚本。


python main.py


然后,我们就可以得到以下图片所示的目标计数GUI。这一次,我将使用一个定制模型来识别我从Ultralytics HUB创建的Pompompurin。

初始阶段

按下“RUN”后,我的新模型知道它现在是一只狗...


接下来,为了让我们的用户更轻松地使用,我们可以创建一个包含以下代码的“cmd”文件。


python main.py
pause


现在,用户可以通过打开cmd文件来使用我们的GUI/应用程序。

相关文章
|
机器学习/深度学习 计算机视觉 知识图谱
YoloV8最新改进手册——高阶篇
本专栏是讲解如何改进Yolov8的专栏。改进方法采用了最新的论文提到的方法。改进的方法包括:增加注意力机制、更换卷积、更换block、更换backbone、更换head、更换优化器等;每篇文章提供了一种到N种改进方法。 评测用的数据集是我自己标注的数据集,里面包含32种飞机。每种改进方法我都做了测评,并与官方的模型做对比。 代码和PDF版本的文章,我在验证无误后会上传到百度网盘中,方便大家下载使用。 这个专栏,求质不求量,争取尽心尽力打造精品专栏!!! 专栏链接: ''' https://blog.csdn.net/m0_47867638/category_12295903
2395 0
|
算法 Go 计算机视觉
【YOLO系列】YOLOv8算法(尖端SOTA模型)
Ultralytics YOLOv8 是由 Ultralytics开发的一个前沿 SOTA 模型。它在以前 YOLO 版本的成功基础上,引入了新的功能和改进,进一步提升了性能和灵活性。YOLOv8 基于快速、准确和易于使用的理念设计,使其成为广泛的物体检测、图像分割和图像分类任务的绝佳选择。
3538 0
【YOLO系列】YOLOv8算法(尖端SOTA模型)
|
机器学习/深度学习 人工智能 运维
人工智能在云计算中的运维优化:智能化的新时代
人工智能在云计算中的运维优化:智能化的新时代
1068 49
|
人工智能 自然语言处理 测试技术
通义灵码一周年
【10月更文挑战第5天】通义灵码一周年体验
275 5
|
XML Android开发 数据格式
【无标题】
【无标题】
158 0
|
编解码 自然语言处理 数据挖掘
Nomic Embed:能够复现的SOTA开源嵌入模型
Nomic-embed-text是2月份刚发布的,并且是一个完全开源的英文文本嵌入模型,上下文长度为8192。它在处理短文和长文本任务方面都超越了现有的模型,如OpenAI的Ada-002和text-embedding-3-small。该模型有137M个参数在现在可以算是非常小的模型了。
1119 1
|
运维 Python Windows
如何通过Python脚本查找并终止占用指定端口的进程
在日常的开发和运维过程中,某些端口被意外占用是一个常见的问题。这种情况可能导致服务无法启动或冲突。本文将介绍如何通过Python脚本查找并终止占用指定端口的进程,以确保系统的正常运行。
|
关系型数据库 Java 分布式数据库
实时计算 Flink版操作报错合集之在使用 Python UDF 时遇到 requests 包的导入问题,提示 OpenSSL 版本不兼容如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
453 5
|
Python
丢弃 Tkinter!几行代码快速生成漂亮 GUI!
Python 的 GUI 框架并不少,其中 Tkinter,wxPython,Qt 和 Kivy 是几种比较主流的框架。此外,还有不少在上述框架基础上封装的简化框架,例如 EasyGUI,PyGUI 和 Pyforms 等。
626 0
丢弃 Tkinter!几行代码快速生成漂亮 GUI!
|
存储 机器学习/深度学习 人工智能
向量数据库:新一代的数据处理工具
向量数据库是一种特殊类型的数据库,它可以存储和处理向量数据。向量数据通常用于表示多维度的数据点,例如在机器学习和人工智能中使用的数据。在向量数据库中,数据被表示为向量,这些向量可以在多维空间中进行比较和搜索。这种数据库的一个关键特性是它能够快速地找到与给定向量最相似的其他向量,这是通过计算向量之间的距离(例如欧氏距离或余弦相似度)来实现的。
3085 0
向量数据库:新一代的数据处理工具