YOLO11目标检测运行推理简约GUI界面

YOLO11推理简约GUI界面

使用方法:

支持pt和onnx格式模型,并且自动检测设备,选择推理设备

选择推理图片所在的文件夹
选择推理后的结果保存地址

选择所需要的置信度阈值

点击开始推理,程序自动运行 并在下方实时显示推理进度

非常方便不用每次都改代码来推理了

界面如下所示:

代码如下:

# -*- coding: utf-8 -*-
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
import os, sys, threading, subprocess
from pathlib import Path
import cv2
import torch
from ultralytics import YOLOclass App(tk.Tk):def __init__(self):super().__init__()self.title("YOLOv11 批量推理 (支持 .pt / .onnx)")self.geometry("540x480")self.resizable(False, False)# 设备信息显示self.device_info = self.get_device_info()tk.Label(self, text=f"检测到的设备: {self.device_info}", fg="blue").place(x=20, y=5)# ---- 权重文件 ----tk.Label(self, text="权重文件 (.pt / .onnx):").place(x=20, y=40)self.ent_w = tk.Entry(self, width=45)self.ent_w.place(x=180, y=40)tk.Button(self, text="浏览", command=lambda: self.browse_file(self.ent_w, [("模型文件", "*.pt *.onnx")])).place(x=460, y=36)# ---- 图片文件夹 ----tk.Label(self, text="图片文件夹:").place(x=20, y=80)self.ent_i = tk.Entry(self, width=45)self.ent_i.place(x=180, y=80)tk.Button(self, text="浏览", command=lambda: self.browse_directory(self.ent_i)).place(x=460, y=76)# ---- 输出文件夹 ----tk.Label(self, text="结果保存到:").place(x=20, y=120)self.ent_o = tk.Entry(self, width=45)self.ent_o.place(x=180, y=120)tk.Button(self, text="浏览", command=lambda: self.browse_directory(self.ent_o)).place(x=460, y=116)# ---- 置信度 ----tk.Label(self, text="置信度阈值:").place(x=20, y=160)self.scale_conf = tk.Scale(self, from_=0.01, to=1.0, resolution=0.01,orient=tk.HORIZONTAL, length=300)self.scale_conf.set(0.35)self.scale_conf.place(x=180, y=140)# ---- 设备选择 ----tk.Label(self, text="推理设备:").place(x=20, y=200)self.device_var = tk.StringVar(value="auto")devices = self.get_available_devices()self.device_combo = ttk.Combobox(self, textvariable=self.device_var, values=devices, width=15, state="readonly")self.device_combo.place(x=180, y=200)# ---- 复选框 ----self.var_empty = tk.BooleanVar(value=True)self.var_box = tk.BooleanVar(value=True)self.var_recursive = tk.BooleanVar(value=False)tk.Checkbutton(self, text="保存无目标的图片", variable=self.var_empty).place(x=20, y=240)tk.Checkbutton(self, text="在结果图片上画框", variable=self.var_box).place(x=220, y=240)tk.Checkbutton(self, text="递归子文件夹", variable=self.var_recursive).place(x=20, y=270)# ---- 运行按钮 / 进度条 ----self.btn_run = tk.Button(self, text="开始推理", width=15, command=self.run_thread)self.btn_run.place(x=20, y=310)self.pb = ttk.Progressbar(self, length=480, mode='determinate')self.pb.place(x=20, y=350)# ---- 日志 ----self.txt = tk.Text(self, height=6, width=70, state="disabled")self.txt.place(x=20, y=380)def get_device_info(self):"""获取设备信息"""if torch.cuda.is_available():gpu_count = torch.cuda.device_count()gpu_name = torch.cuda.get_device_name(0)return f"GPU: {gpu_name} ({gpu_count}个)"else:return "CPU only"def get_available_devices(self):"""获取可用设备列表"""devices = ["auto"]if torch.cuda.is_available():for i in range(torch.cuda.device_count()):devices.append(f"cuda:{i}")devices.append("cpu")return devicesdef browse_file(self, entry, filetypes):"""浏览文件"""f = filedialog.askopenfilename(filetypes=filetypes)if f:entry.delete(0, tk.END)entry.insert(0, f)def browse_directory(self, entry):"""浏览目录"""f = filedialog.askdirectory()if f:entry.delete(0, tk.END)entry.insert(0, f)def log(self, msg):"""日志输出"""self.txt.configure(state="normal")self.txt.insert(tk.END, msg + "\n")self.txt.see(tk.END)self.txt.configure(state="disabled")self.update()# ---------- 推理 ----------def run_thread(self):"""启动推理线程"""if not self.validate():returnself.btn_run.config(state="disabled")self.pb["value"] = 0threading.Thread(target=self.infer, daemon=True).start()def validate(self):"""验证输入"""for e in (self.ent_w, self.ent_i, self.ent_o):if not e.get():messagebox.showerror("提示", "请完整填写路径!")return Falsew_path = Path(self.ent_w.get())if not w_path.exists():messagebox.showerror("错误", "权重文件不存在!")return Falseif w_path.suffix.lower() not in ['.pt', '.onnx']:messagebox.showerror("错误", "只支持 .pt 或 .onnx 格式的权重文件!")return Falsei_path = Path(self.ent_i.get())if not i_path.exists():messagebox.showerror("错误", "图片文件夹不存在!")return Falsereturn Truedef infer(self):"""执行推理"""try:# 获取设备设置device_choice = self.device_var.get()if device_choice == "auto":device = "0" if torch.cuda.is_available() else "cpu"else:device = device_choicew_path = self.ent_w.get()ext = Path(w_path).suffix.lower()self.log(f"正在加载模型,使用设备: {device}...")# 关键修改:初始化时不传递device参数[1,3,4](@ref)model = YOLO(w_path)# 对于PyTorch模型,使用.to()方法迁移到指定设备[6,7](@ref)if ext == '.pt' and device != 'cpu':model.to(device)self.log(f"PyTorch模型已迁移到设备: {device}")elif ext == '.onnx':self.log("注意: ONNX模型当前使用CPU推理,如需GPU加速请使用TensorRT转换")device = 'cpu'in_dir = Path(self.ent_i.get())out_dir = Path(self.ent_o.get())out_dir.mkdir(parents=True, exist_ok=True)# 收集图片文件pattern = '​**​/*' if self.var_recursive.get() else '*'img_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.tiff'}imgs = [p for p in in_dir.glob(pattern)if p.suffix.lower() in img_extensions and p.is_file()]total = len(imgs)if total == 0:messagebox.showwarning("警告", "未找到任何图片!")returnself.pb["maximum"] = totalself.log(f"找到 {total} 张图片,开始推理...")# 批量推理for idx, img_p in enumerate(imgs, 1):rel_path = img_p.relative_to(in_dir) if in_dir in img_p.parents else Path()save_dir = out_dir / rel_path.parentsave_dir.mkdir(parents=True, exist_ok=True)save_img = save_dir / f"{img_p.stem}_result.jpg"# 执行推理,在predict方法中指定设备[1,3,4](@ref)results = model.predict(source=str(img_p),conf=self.scale_conf.get(),save=False,verbose=False,device=device  # 在这里指定设备)result = results[0]if len(result.boxes) == 0 and not self.var_empty.get():continue# 处理结果图像img_out = result.plot() if self.var_box.get() else result.orig_imgcv2.imwrite(str(save_img), img_out)# 更新进度self.pb["value"] = idxself.log(f"[{idx:03d}/{total:03d}] {img_p.name}")# 完成后打开结果文件夹subprocess.Popen(f'explorer "{out_dir}"')messagebox.showinfo("完成", f"推理完成!处理了 {total} 张图片。")except Exception as e:error_msg = f"推理错误: {str(e)}"self.log(error_msg)messagebox.showerror("错误", error_msg)finally:self.btn_run.config(state="normal")self.pb["value"] = 0if __name__ == "__main__":# 在打包环境下调整路径if getattr(sys, 'frozen', False):os.chdir(os.path.dirname(sys.executable))app = App()app.mainloop()

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

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

相关文章

集值优化问题:理论、应用与前沿进展

本文由「大千AI助手」原创发布,专注用真话讲AI,回归技术本质。拒绝神话或妖魔化。搜索「大千AI助手」关注我,一起撕掉过度包装,学习真实的AI技术! 1. 📚 集值优化问题概述 集值优化问题主要研究目标函数为…

提示工程架构师分享:如何用提示词升级职业教育的实操案例教学?(万字长文来袭,高能预警!!!)

引言:实操案例教学的“困境”,终于有了破局思路? 晚上10点,汽修专业的王强老师还在电脑前修改《汽车发动机异响故障排查案例》——这已经是他本周第四次调整方案了: 第一次授课时,学生反馈“案例太理想化&a…

「日拱一码」087 机器学习——SPARROW

目录 SPARROW 介绍 核心思想:稀疏掩码训练 与 Lottery Ticket Hypothesis (LTH) 的关系 代码示例 代码关键点解释: 在机器学习领域,"SPARROW" 并不是一个像 Scikit-learn、TensorFlow 或 PyTorch 那样广为人知的通用框架或算法…

18、决策树与集成学习 - 从单一智慧到群体决策

学习目标:理解决策树的构建原理和分裂标准,掌握信息增益、基尼系数等概念,学会决策树的剪枝方法,深入理解集成学习的思想,掌握随机森林和梯度提升的基本原理。 > 从第17章到第18章:从概率模型到规则模型 在第17章中,我们学习了逻辑回归——一个基于概率的线性分类器…

王道计算机组成原理 学习笔记

第一章计算机系统概述1.1计算机的发展历程1.2计算机系统层次结构1.2.11.2.2 计算机硬件的基本组成1.2.2 各个硬件的工作原理1.2.3 计算机软件1.2.4 计算机系统的层次结1.2.5 计算机系统的工作原理1.3计算机的性能指标第二章数据的表示和运算第三章存储系统第四章指令系统第五章…

Oracle 笔记1 表空间及用户

Oracle 笔记1 表空间及用户1 安装Oracle2 创建表空间3 创建表空间用户1. 核心管理用户2. 示例与工具用户3. 系统与服务用户4. 创建表空间用户5. 修改表空间用户特性OracleMySQL开发商Oracle 公司最初由 MySQL AB 开发,后被 Sun 收购,现属 Oracle 公司数据…

MyBatis主键返回机制解析

关于 MyBatis 主键返回的深入解释 核心问题:信息隔离 数据库和应用程序是两个独立的系统: 数据库在服务器上执行 INSERT 操作并生成主键应用程序在另一个进程或甚至另一台机器上运行如果没有明确的机制,应用程序无法自动知道数据库生成了什么…

【Python】Python内置函数大全解析(附源码)

目录专栏导读前言🚀 功能特性1. 全面的函数覆盖2. 多种查询工具3. 完整的测试验证🛠️ 使用方法基本使用交互式查询运行测试📚 支持的内置函数分类数学运算 (13个)类型转换 (8个)序列操作 (8个)迭代器 (6个)输入输出 (3个)对象操作 (31个)&am…

每日算法题推送

题目1:快乐数 我们先来结合实例看一下判断快乐数的整个过程: 结合题目可以知道,如果一个数是快乐数,那么这个数最终就会变成1,如果一个数不是快乐数,那么变化序列最终就会陷入循环。想一下,如果…

Oracle体系结构-数据文件(Data Files)

一、 数据文件的本质与原理 物理存储的基石: 数据文件是 Oracle 数据库在操作系统层面最核心、最基础的物理存储单元。它们是存储在服务器硬盘(或存储阵列)上的操作系统文件(如 .dbf, .ora 扩展名常见,但非强制&#x…

【C++练习】18.C++求两个整数的最小公倍数(LCM)

目录C求两个整数的最小公倍数(LCM)的方法方法一:利用最大公约数(GCD)计算代码实现方法二:逐次增加法代码实现方法三:质因数分解法代码实现方法比较处理大数和特殊情况改进版GCD方法实现 C求两个整数的最小公倍数(LCM)的方法 最小公倍数(LCM)是…

Linux网络:应用层协议http

前言 虽然我们说,应用层协议是我们程序猿自己定的。但实际上,已经有大佬们定义了一些现成的,又非常好用的应用层协议,供我们直接参考使用.HTTP(超文本传输协议)就是其中之一。 我们之前已经学了UDP与TCP套接字的简单使用,以及讲解了进程间的各种关系&a…

ffmpeg推流测试

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、操作步骤1.测试12.测试2总结前言 提示:这里可以添加本文要记录的大概内容: 环境信息: 摄像头:usb摄像头 &a…

Docker的使用及核心命令

文章目录Docker基础概念镜像管理命令镜像查看和搜索镜像下载和删除镜像构建容器生命周期管理创建和启动容器容器控制命令容器清理容器交互和调试进入容器文件操作日志和监控数据管理数据卷(Volume)绑定挂载网络管理网络基础操作端口映射Dockerfile和Dock…

考研408计算机网络第36题真题解析(2021-2023)

(2023.36)在使用 CSMA/CD 协议的环境中,使用截断二进制指数退避算法,来选择重传时机,算法 有如下规定: (1)基本的退避时间为争用期 2τ,假设某网络具体的争用期为 51.2us…

Asio C++ Library是用来做什么的

hriskohlhoff/asio 是由 Chris Kohlhoff 主导维护的开源 C 库,专注于提供高效、跨平台的异步 I/O 支持,广泛应用于网络编程、并发控制和高性能系统开发。 📘 项目概述 项目名称:Asio C Library 下载地址:https://down…

ac791的按键ad_channel

每次ad_channel这个参数都要给我一定的迷惑性,让我以为这是通道的数量

机器人巡检与巡逻的区别进行详细讲解和对比

机器人巡检与巡逻的区别进行详细讲解和对比 尽管这两个词经常被混用,但在技术和应用层面上,它们有着本质的区别。核心区别在于:巡检是“深度体检”,而巡逻是“治安巡查”。 以下将从多个维度进行详细讲解和对比。 一、核心概念与目…

先进电机拓扑及控制算法介绍(3)——以“数据”驱动电机实现真正的无模型

1. 背景介绍 之前已经介绍过“无模型预测控制(Model-Free Predictive Control/MFPC)”中的“无模型预测电流控制(Model-Free Predictive Current Control/MFPCC)”,可参考下面知乎。 https://zhuanlan.zhihu.com/p/6…

C primer plus (第六版)第十一章 编程练习第5,6题

题目:5.设计并测试⼀个函数,搜索第1个函数形参指定的字符串,在其中查找第2个函数形参指定的字符⾸次出现的位置。如果成功,该函数返指向该字符的指针,如果在字符串中未找到指定字符,则返回空指针…