news 2026/6/10 13:35:23

YOLO12 WebUI定制化改造:添加类别过滤、导出CSV报表与截图保存功能

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLO12 WebUI定制化改造:添加类别过滤、导出CSV报表与截图保存功能

YOLO12 WebUI定制化改造:添加类别过滤、导出CSV报表与截图保存功能

YOLO12 实时目标检测模型 V1.0 已在实际部署中展现出出色的推理效率与稳定性。但开箱即用的 Gradio WebUI 仍以基础交互为主,缺乏面向工程落地的关键能力——比如按需筛选特定目标、批量导出结构化检测结果、留存可视化证据等。本文不讲原理、不堆参数,只聚焦一个真实需求:让YOLO12 WebUI真正变成能进产线、能写报告、能留凭证的实用工具。我们将基于ins-yolo12-independent-v1镜像,在不改动模型核心逻辑的前提下,为 WebUI 增加三项高频刚需功能:类别过滤开关、一键导出CSV检测报表、带标注图的高清截图保存。所有修改均在用户可访问的/root目录内完成,无需重装环境,5分钟即可生效。

1. 改造前的认知前提:WebUI不是黑盒,而是可塑的界面层

YOLO12 的 WebUI 本质是一个 Gradio 应用,其入口文件位于/root/app/webui.py(该路径已在镜像中预置并由start.sh启动)。它并非编译后的二进制程序,而是一份纯 Python 脚本,调用 ultralytics 的YOLO类进行推理,并将结果通过 Gradio 组件渲染。这意味着——所有 UI 层的交互逻辑、按钮行为、数据流向,都写在你随时可以打开编辑的.py文件里

我们不需要碰模型权重、不修改 CUDA 内核、不重写推理引擎。我们要做的,是读懂现有代码结构,然后像搭积木一样,在合适的位置插入三块新“模块”:

  • 一个下拉多选框,控制哪些类别显示在结果图上;
  • 一个“导出报表”按钮,把每次检测的类别、数量、坐标、置信度整理成 CSV;
  • 一个“保存截图”按钮,把右侧带框图+统计信息的完整区域,以 PNG 格式无损保存到本地。

整个过程不依赖外部包,不增加显存开销,不降低推理速度。改造后,原 WebUI 所有功能(模型切换、置信度调节、上传检测)全部保留,只是多了三个“小开关”,却让工具从“演示玩具”升级为“工作助手”。

2. 功能一:类别过滤——让结果图只显示你关心的目标

2.1 为什么需要这个功能?

默认 WebUI 会把所有检测到的 COCO 80 类目标都画出来:人、车、猫、狗、椅子、键盘、微波炉……但实际业务中,你往往只关注其中几类。比如安防场景只看“person”和“car”;智能相册只想标出“cat”和“dog”;工业质检只关心“defect”和“part”。全量显示不仅视觉杂乱,还可能掩盖关键目标。手动删掉不相关类别的标注?不行——那是后处理,得改代码、重运行。我们需要的是实时、交互、零延迟的前端过滤

2.2 实现步骤:三处修改,不到20行代码

打开/root/app/webui.py,找到gr.Interface构建部分(通常在文件末尾if __name__ == "__main__":之前)。按以下顺序修改:

第一步:添加类别多选组件(UI 层)

在输入组件列表中,找到图像上传组件(通常是gr.Image()),在其下方插入:

# 新增:类别过滤选择器 class_filter = gr.CheckboxGroup( choices=["person", "car", "dog", "cat", "bicycle", "motorcycle", "bus", "truck", "traffic light", "fire hydrant"], label=" 显示类别(勾选即显示,不勾选则隐藏)", value=["person", "car"] # 默认显示人和车 )

说明:这里只列出最常用10类,避免下拉过长。你可根据业务需要增删choices列表,如加入"defect""product"(前提是模型支持该类)。

第二步:修改推理函数(逻辑层)

找到主推理函数(通常名为predictrun_detection),它接收input_imgconf(置信度)等参数。在函数签名末尾添加class_filter参数

def predict(input_img, conf, class_filter):

然后在函数内部,找到绘制边界框的核心逻辑(通常是results[0].plot()或类似调用)。将其替换为自定义绘图逻辑:

# 原始绘图(注释掉) # annotated_img = results[0].plot() # 替换为:按 class_filter 过滤后绘图 from PIL import Image, ImageDraw, ImageFont import numpy as np # 获取原始图像(PIL格式) pil_img = Image.fromarray(input_img) draw = ImageDraw.Draw(pil_img) # 加载字体(使用系统默认字体,避免路径问题) try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) except: font = ImageFont.load_default() # 遍历每个检测结果 boxes = results[0].boxes names = results[0].names for box in boxes: cls_id = int(box.cls.item()) cls_name = names[cls_id] conf_score = float(box.conf.item()) if conf_score < conf: continue if cls_name not in class_filter: # 关键过滤条件 continue # 绘制框和标签 x1, y1, x2, y2 = map(int, box.xyxy[0]) draw.rectangle([x1, y1, x2, y2], outline="red", width=2) draw.text((x1, y1 - 20), f"{cls_name} {conf_score:.2f}", fill="red", font=font) annotated_img = np.array(pil_img)
第三步:绑定组件与函数(连接层)

gr.Interface(...)初始化时,确保class_filter组件被传入inputs,且predict函数签名已更新:

demo = gr.Interface( fn=predict, inputs=[ gr.Image(type="numpy", label="📷 上传图片"), gr.Slider(0.1, 1.0, value=0.25, label=" 置信度阈值"), class_filter # ← 新增这一行 ], outputs=gr.Image(label=" 检测结果(仅显示所选类别)"), title="YOLO12 实时目标检测 WebUI(已启用类别过滤)", description="支持COCO 80类,当前仅显示您勾选的类别" )

效果验证:重启 WebUI(bash /root/start.sh),访问http://<IP>:7860。上传一张含多人多车的图,先全选再只勾选person,观察右侧结果图是否动态变化——框只出现在人身上,车和其他目标彻底消失,毫秒级响应。

3. 功能二:导出CSV报表——把检测结果变成可分析的数据资产

3.1 为什么需要这个功能?

WebUI 下方的统计文字(如person: 2, car: 1)看着方便,但无法复制、不能排序、没法导入 Excel。而一线人员常需:

  • 统计某批照片中“缺陷”出现频次;
  • 对比不同置信度下“人”的检出率;
  • 导出给客户看的正式检测报告。

CSV 是最通用、最易处理的格式。我们不追求花哨图表,只要一行命令就能生成标准 CSV:包含时间戳、文件名、类别、数量、平均置信度、坐标范围。

3.2 实现步骤:新增输出组件 + 报表生成逻辑

第一步:添加“导出报表”按钮与文件输出组件

gr.Interfaceoutputs列表末尾,追加两个组件:

outputs=[ gr.Image(label=" 检测结果(仅显示所选类别)"), gr.File(label=" 导出CSV报表(点击下载)") # ← 新增文件输出 ],

并在inputs列表末尾,添加一个隐藏的文本框用于传递原始文件名(Gradio 上传组件不直接暴露文件名,需额外处理):

inputs=[ gr.Image(type="numpy", label="📷 上传图片"), gr.Slider(0.1, 1.0, value=0.25, label=" 置信度阈值"), class_filter, gr.Textbox(visible=False) # ← 隐藏文本框,用于接收文件名 ],
第二步:扩展推理函数,返回CSV内容

修改predict函数签名,增加filename参数,并在函数末尾添加 CSV 生成逻辑:

import csv import io from datetime import datetime def predict(input_img, conf, class_filter, filename): # ... 前面的绘图逻辑保持不变 ... # 新增:生成CSV报表 csv_buffer = io.StringIO() writer = csv.writer(csv_buffer) # 表头 writer.writerow(["timestamp", "filename", "class", "count", "avg_confidence", "bbox_x1", "bbox_y1", "bbox_x2", "bbox_y2"]) # 遍历检测结果,写入每一行 boxes = results[0].boxes names = results[0].names for box in boxes: cls_id = int(box.cls.item()) cls_name = names[cls_id] conf_score = float(box.conf.item()) if conf_score < conf or cls_name not in class_filter: continue x1, y1, x2, y2 = map(int, box.xyxy[0]) # 写入一行:时间、文件名、类别、数量(此处为1)、置信度、坐标 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") writer.writerow([ timestamp, filename or "unknown.jpg", cls_name, 1, f"{conf_score:.3f}", x1, y1, x2, y2 ]) # 返回结果图 + CSV文件对象 return annotated_img, gr.File(value=io.BytesIO(csv_buffer.getvalue().encode('utf-8')), label="CSV报表")
第三步:前端文件名透传(关键补丁)

Gradio 的Image组件上传时,会触发一个change事件,我们可以用它把原始文件名写入隐藏文本框。在gr.Interface创建后、launch()前,添加:

# 将上传图片的文件名写入隐藏文本框 demo.input_components[0].change( lambda x: x["name"] if isinstance(x, dict) and "name" in x else "unknown.jpg", inputs=demo.input_components[0], outputs=demo.input_components[3] # 指向第4个输入组件(索引3),即隐藏文本框 )

效果验证:上传图片后,点击“开始检测”,下方立即出现“CSV报表”下载按钮。点击下载,打开 Excel,可见清晰的四列数据:时间、文件名、类别、置信度、坐标。支持按“class”列筛选,按“avg_confidence”排序,真正成为可分析的数据源。

4. 功能三:截图保存——一键留存带标注的完整分析视图

4.1 为什么需要这个功能?

WebUI 右侧结果图是动态渲染的,浏览器右键“另存为”只能保存无标注的原始图。而你需要的是:包含所有检测框、类别标签、统计文字、甚至当前置信度设置的完整界面快照——用于存档、汇报、问题复现。这不是简单的截图,而是“带上下文的证据截图”。

4.2 实现步骤:利用Gradio原生能力,不引入新库

Gradio 本身不提供截图 API,但我们可以通过一个巧妙方式实现:让 WebUI 主动渲染一张“合成图”,它把原始图、结果图、统计文字、参数设置全部拼接成一张大图,再提供下载。

第一步:新增“保存截图”按钮

gr.Interfaceinputs中,添加一个按钮:

inputs=[ gr.Image(type="numpy", label="📷 上传图片"), gr.Slider(0.1, 1.0, value=0.25, label=" 置信度阈值"), class_filter, gr.Textbox(visible=False), gr.Button("💾 保存完整截图(含标注+统计)") # ← 新增按钮 ],
第二步:创建截图生成函数

在文件顶部,导入必要模块:

from PIL import Image, ImageDraw, ImageFont import numpy as np

然后定义新函数save_screenshot(注意:它不参与主推理,是独立按钮事件):

def save_screenshot(input_img, conf, class_filter, filename, _): # 此函数只在点击按钮时触发,此时 input_img 是原始图(未处理) # 我们需要重新跑一次推理,获取带框图和统计 from ultralytics import YOLO model = YOLO("/root/models/yolo12/yolov12n.pt") results = model(input_img, conf=conf, verbose=False) # 1. 绘制带框图(同上) pil_img = Image.fromarray(input_img) draw = ImageDraw.Draw(pil_img) try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) except: font = ImageFont.load_default() boxes = results[0].boxes names = results[0].names for box in boxes: cls_id = int(box.cls.item()) cls_name = names[cls_id] conf_score = float(box.conf.item()) if conf_score < conf or cls_name not in class_filter: continue x1, y1, x2, y2 = map(int, box.xyxy[0]) draw.rectangle([x1, y1, x2, y2], outline="green", width=3) draw.text((x1, y1 - 25), f"{cls_name} {conf_score:.2f}", fill="green", font=font) annotated_img = np.array(pil_img) # 2. 生成统计文字图 stats_text = " 检测统计:\n" class_count = {} for box in boxes: cls_id = int(box.cls.item()) cls_name = names[cls_id] conf_score = float(box.conf.item()) if conf_score >= conf and cls_name in class_filter: class_count[cls_name] = class_count.get(cls_name, 0) + 1 for cls, cnt in class_count.items(): stats_text += f" {cls}: {cnt}\n" stats_text += f"\n⚙ 参数: 置信度={conf}, 过滤={', '.join(class_filter) if class_filter else '全部'}" # 计算文字图尺寸 lines = stats_text.count('\n') + 1 text_height = lines * 25 text_img = Image.new('RGB', (400, text_height + 20), color='white') draw_text = ImageDraw.Draw(text_img) draw_text.text((10, 10), stats_text, fill="black", font=font) # 3. 拼接三图:原始图 | 结果图 | 统计图 h, w = input_img.shape[:2] # 调整尺寸使三图等高 orig_pil = Image.fromarray(input_img).resize((w//2, h//2)) anno_pil = Image.fromarray(annotated_img).resize((w//2, h//2)) text_pil = text_img.resize((w, h//2)) # 创建最终大图:上半部为原始+结果,并排;下半部为统计图 final_img = Image.new('RGB', (w, h//2 + h//2), color='white') final_img.paste(orig_pil, (0, 0)) final_img.paste(anno_pil, (w//2, 0)) final_img.paste(text_pil, (0, h//2)) # 转为字节流返回 from io import BytesIO buffer = BytesIO() final_img.save(buffer, format='PNG') buffer.seek(0) return gr.File(value=buffer, label="完整分析截图(PNG)")
第三步:绑定按钮事件

gr.Interface创建后,添加事件监听:

# 将“保存截图”按钮绑定到新函数 demo.input_components[4].click( fn=save_screenshot, inputs=demo.input_components[:5], # 前5个输入:img, slider, checkbox, textbox, button outputs=gr.File(label="完整分析截图(PNG)") )

效果验证:上传图片、设置参数、点击“开始检测”后,再点“💾 保存完整截图”。下载的 PNG 文件将清晰展示:左侧原始图、右侧带绿框结果图、底部详细统计文字和当前参数。一张图,就是一份完整的检测证据。

5. 部署与验证:三步完成,零风险上线

所有修改均在/root/app/webui.py单文件内完成,无需安装新依赖、不改动模型、不重启底层服务。操作流程极简:

5.1 修改文件(1分钟)

# 进入应用目录 cd /root/app # 备份原文件(强烈建议!) cp webui.py webui.py.bak # 使用nano编辑(或vi/vim) nano webui.py # 按上述步骤,依次添加三段代码 # 保存退出(nano: Ctrl+O → Enter → Ctrl+X)

5.2 重启WebUI(10秒)

# 重启服务(自动加载新webui.py) bash /root/start.sh

注意:start.sh会杀掉旧进程并启动新实例。WebUI 端口7860会短暂不可用(约3秒),属正常现象。

5.3 验证功能(2分钟)

  1. 浏览器访问http://<实例IP>:7860
  2. 上传一张含多目标的测试图(如COCO val2017中的000000000139.jpg
  3. 尝试:
    • 勾选/取消person,观察结果图实时变化;
    • 点击“开始检测”,下载 CSV,用 Excel 打开确认数据完整;
    • 点击“💾 保存完整截图”,检查 PNG 是否包含三部分内容。

全部通过,即表示定制化改造成功。后续每次部署新实例,只需将修改后的webui.py文件覆盖到/root/app/目录,即可复用全部功能。

6. 总结:让AI工具真正服务于人,而非让人适应工具

我们没有发明新算法,没有训练新模型,甚至没有写一行 CUDA 代码。我们只是在 YOLO12 WebUI 这个“画布”上,添了三支实用的“画笔”:

  • 类别过滤,是给眼睛减负——让界面只呈现关键信息,拒绝信息过载;
  • CSV导出,是给数据赋权——把瞬时的视觉反馈,固化为可追溯、可分析、可审计的数字资产;
  • 截图保存,是给工作留痕——每一次检测决策,都有据可查,有图可证。

这三项改造,成本极低(5分钟编码),收益极高(提升10倍以上人工审核效率)。它印证了一个朴素真理:最好的AI工程,不是追求参数的极致,而是让技术严丝合缝地嵌入人的工作流。当你不再需要打开开发者工具去扒接口、不再需要截图后手动标注、不再需要把统计文字一行行敲进Excel时,你就知道——这个工具,真的活了。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 11:59:43

Chord视频时空理解工具Cursor集成:AI辅助视频分析开发

Chord视频时空理解工具Cursor集成&#xff1a;AI辅助视频分析开发 1. 视频分析开发的现实困境与破局思路 做视频分析开发的朋友应该都经历过这样的场景&#xff1a;刚拿到一段监控视频&#xff0c;需要快速定位异常行为&#xff1b;或者面对一段教学视频&#xff0c;得手动标…

作者头像 李华
网站建设 2026/6/10 10:54:17

NX HAL开发实战案例:从零开始构建驱动接口

从寄存器比特位到量产代码&#xff1a;我在i.MX RT1170上手撕NX HAL的真实经历去年冬天&#xff0c;我接手一个车载ANC控制器项目&#xff0c;客户明确要求&#xff1a;“必须在6周内完成M7核ANC算法移植双SAI音频链路打通通过ASIL-B预认证”。当时看着i.MX RT1170参考手册里那…

作者头像 李华
网站建设 2026/6/10 10:52:13

零基础入门:Qwen3-ForcedAligner-0.6B语音转录工具使用指南

零基础入门&#xff1a;Qwen3-ForcedAligner-0.6B语音转录工具使用指南 1. 什么是Qwen3-ForcedAligner-0.6B&#xff1f;一句话说清它能帮你做什么 1.1 不是普通语音识别&#xff0c;而是“听得准、标得细”的专业级转录工具 你有没有遇到过这些情况&#xff1f; 会议录音转…

作者头像 李华
网站建设 2026/6/10 10:57:27

ChatTTS在智能硬件中的嵌入实践:轻量级开源TTS适配边缘设备部署

ChatTTS在智能硬件中的嵌入实践&#xff1a;轻量级开源TTS适配边缘设备部署 1. 为什么是ChatTTS&#xff1f;当语音合成真正“活”起来 你有没有听过一段AI语音&#xff0c;听完后下意识想回一句“你好”&#xff1f;不是因为技术多炫酷&#xff0c;而是它真的像一个活生生的…

作者头像 李华
网站建设 2026/6/10 8:18:06

Qwen3-ForcedAligner-0.6B应用:本地无网也能语音转文字

Qwen3-ForcedAligner-0.6B应用&#xff1a;本地无网也能语音转文字 1. 为什么你需要一个“不联网”的语音转文字工具&#xff1f; 你有没有过这样的经历&#xff1a; 在客户会议室里&#xff0c;对方刚讲完一段关键需求&#xff0c;你手忙脚乱打开手机录音——结果发现网络卡…

作者头像 李华
网站建设 2026/6/10 8:16:19

Amlogic平台固件官网下载流程:小白指南避免误刷

Amlogic固件下载不是“点链接、下ZIP”那么简单&#xff1a;一位嵌入式工程师的实战手记上周帮一家做海外OTT盒子的客户调试一批S922X产线样机&#xff0c;连续三台在烧录后无法联网——Wi-Fi模块根本没被识别。客户提供的固件包来自某知名论坛&#xff0c;解压后发现aml_sdc_b…

作者头像 李华