date: 2025-02-11 19:52:04
tags:
-相关内容
一,使用labelimg制作数据集
1.anoconda虚拟环境下使用 pip install labelimg
安装labelimg工具输入labelimg打开软件,接下来可以对图片进行标志并生成相关格式标签文件
2.数据集文件夹包含以下3类文件
class相关类名
image文件夹里是划分好的train集和val集
lable文件夹里也是划分好的train集和val集
二,YOLOv11训练模型
1.可以anoconda搭载好环境包含ultralytics,python版本不能较老,集安装好pytorch,电脑有gpu可以下gpu版本训练快很多
1.在github官网下载对应版本ultralytics及yolov11n.pt文件
用pycharm等打开ultralytics项目
2.yaml中填写好相关路径
3.创建train.py文件写训练代码如
4.运行代码,等待训练结束
生成的runs文件夹里含训练出的模型权重文件best.pt
三,PyQt6开发界面及编写代码
1.搭载好pyqt6及pyqt6-tools环境
2.打开QTdesiger设计
包含两个pushButton组件分别实现文件上传功能及电脑摄像头开关功能
objectName分别为uploadButton,cameraButton(代码中会引用这些属性)
一个Qtextedit组件objectName:statusTextEdit来呈现统计信息
一个Qlabel组件,objectName:resultLabel展示图片或视频标注结果
可用一些设计美化界面
四,代码
1.所需相关模块
import sys :sys.argv:用于获取命令行参数,在 QApplication(sys.argv) 中,将命令行参数传递给 QApplication
sys.exit(app.exec()):用于在应用程序结束时退出 Python 解释器
import cv2 :cv2.VideoCapture:用于打开视频文件或摄像头设备,如 cv2.VideoCapture(self.file_path) 用于打开视频文件,cv2.VideoCapture(0) 用于打开默认摄像头。
cap.read():从视频文件或摄像头中读取一帧图像。
from ultralytics import YOLO :self.model = YOLO(‘best.pt’) 加载了YOLO 模型,对图像和视频帧进行目标检测,如 results = self.model(frame)。
from PyQt6 import uic:加载 QtDesigner 创建的 UI 文件。在代码中,uic.loadUi(‘task3.ui’, self) 加载名为 task3.ui 的 UI 文件到 MainWindow 类中。
from PyQt6.QtWidgets import QApplication, QWidget, QFileDialog
QApplication:应用程序的控制和设置
QWidget:用于创建自定义的窗口界面,MainWindow类继承自QWidget
QFileDialog:实现打开文件功能,连接pushbutton
from PyQt6.QtGui import QPixmap, QImage
QPixmap:显示图像 (QLabel)
QImage:处理和操作图像数据
from PyQt6.QtCore import QThread, pyqtSignal
QThread:QThread 创建多线程,我创建了VideoThread 和 CameraThread ,继承于QThread,在后台处理视频和摄像头数据。
pyqtSignal:不同线程之间传递信号,frame_processed = pyqtSignal(object, object) 定义了一个信号,用于传递处理后的帧和统计信息。
from PyQt6.QtCore import QResource:运行二进制资源文件,
我使用了.qrc文件提供图片,$ "相关路径\Lib\site-packages\qt6_applications\Qt\bin\rcc.exe" "-binary" "1.qrc" "-o" "1.rcc"
命令把.qrc编译成二进制
QResource.registerResource('.rcc')
代码实现图片展示功能
2.相关类
VideoThread
pythonclass VideoThread(QThread):
frame_processed = pyqtSignal(object, object)
def init(self, file_path, model):
…
def reset_counts(self):
…
def run(self):
…
def stop(self):
…
继承自 QThread,用于在后台处理视频文件。其主要功能包括:
初始化时接收视频文件路径和 YOLO 模型。
run 方法会逐帧读取视频文件,使用 YOLO 模型进行目标检测,统计目标数量,并通过 frame_processed 信号将处理后的帧和统计信息发送出去。
stop 方法用于停止线程的运行。
CameraThread
class CameraThread(QThread):
frame_processed = pyqtSignal(object, object)
def init(self, model):
…
def reset_counts(self):
…
def run(self):
…
def stop(self):
…
继承自 QThread,用于处理摄像头的实时视频流
run 方法会逐帧读取视频文件,使用 YOLO 模型进行目标检测,统计目标数量,并通过 frame_processed 信号将处理后的帧和统计信息发送出去。
stop 方法用于停止线程的运行
3.主窗口class MainWindow(QWidget):
def init(self):
…
def openfile(self):
…
def process_image(self, file_path):
…
def process_video(self, file_path):
…
def update_frame(self, annotated_frame, status_text):
…
def toggle_camera(self):
…
def closeEvent(self, event):
…
继承自 QWidget:init 方法:加载 UI 连接按钮的点击事件
openfile方法:打开文件选择界面
process_image 方法:对用户选择的图像文件进行目标检测,将检测结果显示在界面上,并更新统计信息。
process_video 方法:停止之前的视频处理线程和摄像头线程,创建并启动新的视频处理线程。
update_frame方法:接收处理后的帧和统计信息:切换摄像头的启动和停止状态
closeEvent 方法:在关闭窗口时停止所有正在运行的线程。
4.主程序
if name == ‘main‘:
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec())
五,功能展示
完整代码
import warnings
import cv2
from PyQt6 import uic
from PyQt6.QtWidgets import QApplication, QWidget, QFileDialog
from PyQt6.QtGui import QPixmap, QImage
from PyQt6.QtCore import QThread, pyqtSignal
from ultralytics import YOLO
from PyQt6.QtCore import QResource
warnings.filterwarnings("ignore", category=DeprecationWarning) # 忽略警告
class VideoThread(QThread):
frame_processed = pyqtSignal(object, object) # 信号:传递处理后的帧和统计信息
def __init__(self, file_path, model):
super().__init__()
self.file_path = file_path
self.model = model
self.reset_counts()
self.running = True
def reset_counts(self):
#重置目标数量统计信息
self.class_counts = {}
def run(self):
self.reset_counts()
cap = cv2.VideoCapture(self.file_path)
if not cap.isOpened():
print("Failed to open video file")
return
while self.running:
ret, frame = cap.read()
if not ret:
break
results = self.model(frame)
annotated_frame = results[0].plot() # 绘制检测结果
# 目标统计
class_names = results[0].names
self.class_counts = {} # 重置统计信息
for cls in results[0].boxes.cls.cpu().numpy():
cls_name = class_names[int(cls)]
if cls_name in self.class_counts:
self.class_counts[cls_name] += 1
else:
self.class_counts[cls_name] = 1
status_text = "\n".join([f"{name}: {count}" for name, count in self.class_counts.items()])
self.frame_processed.emit(annotated_frame, status_text) # 发送处理后的帧和统计信息
self.msleep(30) # 每 30 毫秒处理一帧
cap.release()
def stop(self):
self.running = False
self.wait()
class CameraThread(QThread):
frame_processed = pyqtSignal(object, object) # 信号:传递处理后的帧和统计信息
def __init__(self, model):
super().__init__()
self.model = model
self.reset_counts()
self.running = True
def reset_counts(self):
self.class_counts = {}
def run(self):
self.reset_counts()
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Failed to open camera")
return
print("Camera opened successfully")
while self.running:
ret, frame = cap.read()
if not ret:
break
results = self.model(frame)
annotated_frame = results[0].plot() # 绘制检测结果
class_names = results[0].names
self.class_counts = {} # 重置统计信息
for cls in results[0].boxes.cls.cpu().numpy():
cls_name = class_names[int(cls)]
if cls_name in self.class_counts:
self.class_counts[cls_name] += 1
else:
self.class_counts[cls_name] = 1
status_text = "\n".join([f"{name}: {count}" for name, count in self.class_counts.items()])
self.frame_processed.emit(annotated_frame, status_text) # 发送处理后的帧和统计信息
self.msleep(30) # 每 30 毫秒处理一帧
cap.release()
def stop(self):
self.running = False
self.wait()
class MainWindow(QWidget):
def __init__(self):
super().__init__()
uic.loadUi('task3.ui', self)# 加载 UI 文件
self.model = YOLO('best.pt')
self.uploadButton.clicked.connect(self.openfile)
self.cameraButton.clicked.connect(self.toggle_camera) # 新增摄像头按钮点击事件
self.video_thread = None # 视频处理线程
self.camera_thread = None # 摄像头处理线程
self.camera_running = False # 摄像头是否正在运行的标志
def openfile(self):
if self.camera_thread and self.camera_running:
self.toggle_camera() # 停止摄像头
file_path, _ = QFileDialog.getOpenFileName(self, '选择文件', '',
'图片和视频文件 (*.jpg *.png *.mp4 *.webp *.wmv *.bmp *.jpeg *.gif *.avi *.mkv *.flv *.rmvb *.tiff *.mov *.m4v *.3gp *.jfif *.heic)')
if file_path:
# 定义图片文件扩展名元组,添加新的扩展名
image_extensions = ('.jpg', '.png', '.webp', '.bmp', '.jpeg', '.gif', '.tiff', '.jfif', '.heic')
# 定义视频文件扩展名元组,添加新的扩展名
video_extensions = ('.mp4', '.wmv', '.avi', '.mkv', '.flv', '.rmvb', '.mov', '.m4v', '.3gp')
if file_path.lower().endswith(image_extensions):
self.process_image(file_path)
elif file_path.lower().endswith(video_extensions):
self.process_video(file_path)
def process_image(self, file_path):
results = self.model(file_path)
annotated_frame = results[0].plot()
height, width, channel = annotated_frame.shape
bytes_per_line = 3 * width
q_img = QImage(annotated_frame.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
pixmap = QPixmap.fromImage(q_img)
self.resultLabel.setPixmap(pixmap.scaled(self.resultLabel.width(), self.resultLabel.height()))
class_names = results[0].names # 统计信息
class_counts = {}
for cls in results[0].boxes.cls.cpu().numpy():
cls_name = class_names[int(cls)]
if cls_name in class_counts:
class_counts[cls_name] += 1
else:
class_counts[cls_name] = 1
status_text = "\n".join([f"{name}: {count}" for name, count in class_counts.items()])
self.statusTextEdit.setPlainText(status_text)
def process_video(self, file_path):
if self.video_thread:
self.video_thread.stop() # 停止上一个线程
if self.camera_thread and self.camera_running:
self.toggle_camera() # 停止摄像头
# 创建并启动视频处理线程
self.video_thread = VideoThread(file_path, self.model)
self.video_thread.frame_processed.connect(self.update_frame)
self.video_thread.start()
def update_frame(self, annotated_frame, status_text):
try:
height, width, channel = annotated_frame.shape# 将 OpenCV 帧转换为 QImage
bytes_per_line = 3 * width
q_img = QImage(annotated_frame.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
pixmap = QPixmap.fromImage(q_img) # 将 QImage 转换为 QPixmap 并显示
if pixmap.isNull():
print("Pixmap is null!")
else:
self.resultLabel.setPixmap(pixmap.scaled(self.resultLabel.width(), self.resultLabel.height()))
self.statusTextEdit.setPlainText(status_text)
except Exception as e:
print(f"Error updating frame: {e}")
def toggle_camera(self):
if self.camera_running:
# 停止摄像头
self.camera_thread.stop()
self.camera_thread = None
self.camera_running = False
self.cameraButton.setText("启动摄像头")
else:
# 启动摄像头
if self.video_thread:
self.video_thread.stop() # 停止视频处理线程
self.camera_thread = CameraThread(self.model)
self.camera_thread.frame_processed.connect(self.update_frame)
self.camera_thread.start()
self.camera_running = True
self.cameraButton.setText("停止摄像头")
def closeEvent(self, event): #关闭窗口时停止所有线程
if self.video_thread:
self.video_thread.stop()
if self.camera_thread:
self.camera_thread.stop()
event.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
QResource.registerResource('1.rcc')
window.show()
sys.exit(app.exec())```
评论区
欢迎你留下宝贵的意见,昵称输入QQ号会显示QQ头像哦~