本文的可视化界面对于YOLOv11/Ultralytics/YOLOv8的检测、分割、分类、姿势估算(detection, segmentation, obb, classification, and pose estimation)等均可正常显示。本次新增了图片及视频的保存,可以选择传入文件夹进行检测并显示,可以对本地摄像头或者云摄像头获取的视频进行分段保存,本文仅针对图像处理部分给出代码示例,所有代码只需要在根目录下新建一个main.py即可正常运行,对于视频及摄像头处理可以根据图像处理进行修改后实现功能,或者私聊购买成品,之前购买过的可私信我免费获取最新的代码。
目录
1.准备工作
1.1 YOLOv11(Ultralytics)源码获取
YOLOv11官方地址为 https://github.com/ultralytics/ultralyticshttps://github.com/ultralytics/ultralytics
1.2 YOLOv11环境配置
环境异常请根据下文配置相应python环境,再尝试使用本文提供的可视化界面。
建议使用Anaconda3+pycharm,下载8.3.20版本源码。
2.完整界面展示
2.1 主界面展示
界面整体分为三部分,左右图像展示框以及下方功能按钮,下图为运行后界面展示
2.2 功能展示
首先选择模型,选择完之后可以分别点击图片检测选择单张图片检测后显示在界面上,可点击保存到指定位置,点击文件夹检测可以选择一个文件夹后将其按照一定的速度展示,文件夹检测会将检测结果自动保存,视频检测完可以选择保存视频,也可以在检测过程中将视频分段保存,摄像头可选本地和云摄像头,本地会自动获取摄像头编号可选择,云摄像头则需要输入ip后开始检测,均可点击保存为视频。检测之后的图像会实时显示在界面上,左边显示原始图像,右边显示检测后的图像。
也可以选择视频进行检测,效果如下图,可以点击查看当前检测到的所有物体。
2.3 完整功能展示
每个按钮的功能及云摄像头的调用都试了一下,效果如下图。
需要完整功能代码可私信或者在公众号获取,有其它需求可联系定制。
3.界面实现
本文仅对图片检测进行展示,如需其它功能界面请私聊或在公众号获取。
3.1 相关库
除了yolov11所用库之外,本文所用到的额外库为pyqt5,输入指令进行安装
pip install PyQt5
3.2 导入库
我这里导入的是以下这些,同官方源码兼容。
import sys
import os
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QFileDialog, QMessageBox
from PyQt5.QtGui import QImage, QPixmap, QIcon
import cv2
from ultralytics import YOLO
3.3 功能实现
3.3.1 添加按钮
这里实现了权重选择和选择图片及选择文件夹功能并添加了对应的按钮
# 添加模型选择按钮
self.load_model_button = QPushButton("👆模型选择")
self.load_model_button.clicked.connect(self.load_model)
self.load_model_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.load_model_button)
# 添加图片检测按钮
self.image_detect_button = QPushButton("🖼️️图片检测")
self.image_detect_button.clicked.connect(self.select_image)
self.image_detect_button.setEnabled(False)
self.image_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.image_detect_button)
# 添加图片文件夹检测按钮
self.folder_detect_button = QPushButton("️📁文件夹检测")
self.folder_detect_button.clicked.connect(self.detect_folder)
self.folder_detect_button.setEnabled(False)
self.folder_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.folder_detect_button)
# 添加显示检测物体按钮
self.display_objects_button = QPushButton("🔍显示检测物体")
self.display_objects_button.clicked.connect(self.show_detected_objects)
self.display_objects_button.setEnabled(False)
self.display_objects_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.display_objects_button)
# # 添加保存检测结果按钮
self.save_button = QPushButton("💾保存检测结果")
self.save_button.clicked.connect(self.save_detection)
self.save_button.setEnabled(False)
self.save_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.save_button)
# 添加退出按钮
self.exit_button = QPushButton("❌退出")
self.exit_button.clicked.connect(self.exit_application)
self.exit_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.exit_button)
3.3.2 功能函数定义
检测图片并分别在左右窗口进行显示
def detect_image(self, image_path):
if image_path:
print(image_path)
image = cv2.imread(image_path)
if image is not None:
if self.flag == 0:
results = self.worker.model.predict(image)
elif self.flag == 1:
results = self.worker.model.predict(image_path, save=True)
self.worker.detection_type = "image"
if results:
self.current_results = results
self.worker.current_annotated_image = results[0].plot()
annotated_image = self.worker.current_annotated_image
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
height1, width1, channel1 = image_rgb.shape
bytesPerLine1 = 3 * width1
qimage1 = QImage(image_rgb.data, width1, height1, bytesPerLine1, QImage.Format_RGB888)
pixmap1 = QPixmap.fromImage(qimage1)
self.label1.setPixmap(pixmap1.scaled(self.label1.size(), Qt.KeepAspectRatio))
annotated_image = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
height2, width2, channel2 = annotated_image.shape
bytesPerLine2 = 3 * width2
qimage2 = QImage(annotated_image.data, width2, height2, bytesPerLine2, QImage.Format_RGB888)
pixmap2 = QPixmap.fromImage(qimage2)
self.label2.setPixmap(pixmap2.scaled(self.label2.size(), Qt.KeepAspectRatio))
self.save_button.setEnabled(True)
加载模型部分代码
def load_model(self):
model_path, _ = QFileDialog.getOpenFileName(None, "选择模型文件", "", "模型文件 (*.pt)")
if model_path:
self.model = YOLO(model_path)
return self.model is not None
return False
选择图片/文件夹部分代码
def select_image(self):
image_path, _ = QFileDialog.getOpenFileName(None, "选择图片文件", "", "图片文件 (*.jpg *.jpeg *.png)")
self.flag = 0
if image_path:
self.detect_image(image_path)
def detect_folder(self):
folder_path = QFileDialog.getExistingDirectory(self, "选择图片文件夹")
self.flag = 1
if folder_path:
image_paths = []
for filename in os.listdir(folder_path):
if filename.lower().endswith((".jpg", ".jpeg", ".png")):
image_path = os.path.join(folder_path, filename)
image_paths.append(image_path)
for image_path in image_paths:
self.detect_image(image_path)
3.3.3 完整代码
完整代码如下,全部复制后粘贴进一个空白的py文件即可运行,想要调整文件夹下图片切换速度可以修改 cv2.waitKey(300) 的参数,1秒为1000
import sys
import os
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QPushButton, QHBoxLayout, QFileDialog, QMessageBox
from PyQt5.QtGui import QImage, QPixmap, QIcon
import cv2
from ultralytics import YOLO
class Worker:
def __init__(self):
self.model = None
self.current_annotated_image = None
self.detection_type = None
def load_model(self):
model_path, _ = QFileDialog.getOpenFileName(None, "选择模型文件", "", "模型文件 (*.pt)")
if model_path:
self.model = YOLO(model_path)
if self.model:
return True
else:
return False
def detect_objects(self, frame):
det_info = []
class_ids = frame[0].boxes.cls
class_names_dict = frame[0].names
for class_id in class_ids:
class_name = class_names_dict[int(class_id)]
det_info.append(class_name)
return det_info
def save_image(self, image):
if image is not None:
file_name, _ = QFileDialog.getSaveFileName(None, "保存图片", "", "JPEG (*.jpg);;PNG (*.png);;All Files (*)")
if file_name:
cv2.imwrite(file_name, image)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("@author:笑脸惹桃花")
#self.setWindowIcon(QIcon("icon.png"))
self.setGeometry(300, 150, 1200, 600)
# 创建两个 QLabel 分别显示左右图像
self.label1 = QLabel()
self.label1.setAlignment(Qt.AlignCenter)
self.label1.setMinimumSize(580, 450) # 设置大小
self.label1.setStyleSheet('border:3px solid #6950a1; background-color: black;') # 添加边框并设置背景颜色为黑色
self.label2 = QLabel()
self.label2.setAlignment(Qt.AlignCenter)
self.label2.setMinimumSize(580, 450) # 设置大小
self.label2.setStyleSheet('border:3px solid #6950a1; background-color: black;') # 添加边框并设置背景颜色为黑色
# 水平布局,用于放置左右两个 QLabel
layout = QVBoxLayout()
hbox_video = QHBoxLayout()
hbox_video.addWidget(self.label1)
hbox_video.addWidget(self.label2)
layout.addLayout(hbox_video)
self.worker = Worker()
# 创建按钮布局
hbox_buttons = QHBoxLayout()
# 添加模型选择按钮
self.load_model_button = QPushButton("👆模型选择")
self.load_model_button.clicked.connect(self.load_model)
self.load_model_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.load_model_button)
# 添加图片检测按钮
self.image_detect_button = QPushButton("🖼️️图片检测")
self.image_detect_button.clicked.connect(self.select_image)
self.image_detect_button.setEnabled(False)
self.image_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.image_detect_button)
# 添加图片文件夹检测按钮
self.folder_detect_button = QPushButton("️📁文件夹检测")
self.folder_detect_button.clicked.connect(self.detect_folder)
self.folder_detect_button.setEnabled(False)
self.folder_detect_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.folder_detect_button)
# 添加显示检测物体按钮
self.display_objects_button = QPushButton("🔍显示检测物体")
self.display_objects_button.clicked.connect(self.show_detected_objects)
self.display_objects_button.setEnabled(False)
self.display_objects_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.display_objects_button)
# # 添加保存检测结果按钮
self.save_button = QPushButton("💾保存检测结果")
self.save_button.clicked.connect(self.save_detection)
self.save_button.setEnabled(False)
self.save_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.save_button)
# 添加退出按钮
self.exit_button = QPushButton("❌退出")
self.exit_button.clicked.connect(self.exit_application)
self.exit_button.setFixedSize(120, 30)
hbox_buttons.addWidget(self.exit_button)
layout.addLayout(hbox_buttons)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def save_detection(self):
detection_type = self.worker.detection_type
if detection_type == "image":
self.save_detection_results()
def select_image(self):
image_path, _ = QFileDialog.getOpenFileName(None, "选择图片文件", "", "图片文件 (*.jpg *.jpeg *.png)")
self.flag = 0
if image_path:
self.detect_image(image_path)
def detect_folder(self):
folder_path = QFileDialog.getExistingDirectory(self, "选择图片文件夹")
self.flag = 1
if folder_path:
image_paths = []
for filename in os.listdir(folder_path):
if filename.lower().endswith((".jpg", ".jpeg", ".png")):
image_path = os.path.join(folder_path, filename)
image_paths.append(image_path)
for image_path in image_paths:
self.detect_image(image_path)
def detect_image(self, image_path):
if image_path:
print(image_path)
image = cv2.imread(image_path)
if image is not None:
if self.flag == 0:
results = self.worker.model.predict(image)
elif self.flag == 1:
results = self.worker.model.predict(image_path, save=True)
self.worker.detection_type = "image"
if results:
self.current_results = results
self.worker.current_annotated_image = results[0].plot()
annotated_image = self.worker.current_annotated_image
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
height1, width1, channel1 = image_rgb.shape
bytesPerLine1 = 3 * width1
qimage1 = QImage(image_rgb.data, width1, height1, bytesPerLine1, QImage.Format_RGB888)
pixmap1 = QPixmap.fromImage(qimage1)
self.label1.setPixmap(pixmap1.scaled(self.label1.size(), Qt.KeepAspectRatio))
annotated_image = cv2.cvtColor(annotated_image, cv2.COLOR_BGR2RGB)
height2, width2, channel2 = annotated_image.shape
bytesPerLine2 = 3 * width2
qimage2 = QImage(annotated_image.data, width2, height2, bytesPerLine2, QImage.Format_RGB888)
pixmap2 = QPixmap.fromImage(qimage2)
self.label2.setPixmap(pixmap2.scaled(self.label2.size(), Qt.KeepAspectRatio))
self.save_button.setEnabled(True)
cv2.waitKey(300) # 修改图片切换时间
def save_detection_results(self):
if self.worker.current_annotated_image is not None:
self.worker.save_image(self.worker.current_annotated_image)
def show_detected_objects(self):
frame = self.current_results
if frame:
det_info = self.worker.detect_objects(frame)
if det_info:
object_count = len(det_info)
object_info = f"识别到的物体总个数:{object_count}\n"
object_dict = {}
for obj in det_info:
if obj in object_dict:
object_dict[obj] += 1
else:
object_dict[obj] = 1
sorted_objects = sorted(object_dict.items(), key=lambda x: x[1], reverse=True)
for obj_name, obj_count in sorted_objects:
object_info += f"{obj_name}: {obj_count}\n"
self.show_message_box("识别结果", object_info)
else:
self.show_message_box("识别结果", "未检测到物体")
def show_message_box(self, title, message):
msg_box = QMessageBox(self)
msg_box.setWindowTitle(title)
msg_box.setText(message)
msg_box.exec_()
def load_model(self):
if self.worker.load_model():
self.image_detect_button.setEnabled(True)
self.folder_detect_button.setEnabled(True)
self.display_objects_button.setEnabled(True)
def exit_application(self):
sys.exit()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
使用本代码仅需在Ultralytics文件夹中新建一个main.py或者其它名字的py文件然后运行即可,运行有报错可以发在评论区,看到都会及时回复。
3.4 界面展示
这样一个简单的ui界面就写好了。
需要更多功能的及其他需求可以私信,遇到报错可以在评论区交流,关注公众号获取更多资源~