Skip to content

Latest commit

 

History

388 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

🔍 Snet.VisualIdentity

Snet Logo

基于 .NET 10 的 YOLO + Anomalib 工业视觉检测平台

🚀 高效 · 🧩 灵活 · 📦 易部署 · 🔒 安全

🌐 官方网站 · 📦 GitHub · 🎬 演示视频 · 📦 NuGet

📖 English | 简体中文

📑 目录

🌟 项目简介 🎯 应用场景 🏗️ 项目架构
⚡ 快速开始 🏷️ Tasks 工作台 🎬 视频与 FFmpeg
🖥️ 界面展示 📦 NuGet 安装 🔌 API 接口
⚙️ 配置文件 🧠 支持的任务 🖥️ 执行提供者
🐳 Docker 部署 🧪 测试 🔒 安全特性

🌟 项目简介

VisualIdentity 是基于 .NET 10 的视觉检测平台,提供项目管理、图片标注、模型训练、ONNX 验证与 API 服务。YOLO 支持目标检测、分类、实例分割、姿态估计和定向检测五类任务,用已标注的数据识别目标或已知缺陷;Anomalib 使用正常图片训练异常检测模型,定位与正常状态不同的区域,无需逐一标注缺陷类型。两类模型分别管理,共用 Snet.Yolo.Server 中的识别能力,并提供 CPU 与 CUDA 版本。

在工业质检中,可以先用 Anomalib 回答「异常在哪里」,再用训练过对应缺陷类别的 YOLO 回答「这是什么缺陷」。Tasks 的「联合验证」页可自动选取当前用户已有的两类模型,对同一张图片依次识别并关联结果;也可分别运行单模型,对照识别效果。

验证链路直接调用同进程的 Snet.Yolo.Server,不经 HTTP API:YOLO 模型的上传登记与按用户查询复用 ManageOperate,识别由 Server 的 YOLO 推理服务执行;Anomalib 模型包由 AnomalibModelRegistry 管理,推理由 Server 的 ONNX 组件执行。联合验证也在 Server 内查询两类模型、执行识别并关联结果。Tasks 负责页面、上传进度、当前用户身份和视频调度。

💡 当前解决方案统一使用 .NET 10;WPF 工具目标框架为 net10.0-windows。

✨ 核心特性(功能总览)

🧠 识别与模型

特性 说明
🎯 YOLO 五类任务 对象检测 · 定向检测 (OBB) · 图像分类 · 实例分割 · 姿态估计,统一管理、按需切换
🔎 Anomalib 异常定位 仅用正常图片训练 PaDiM 或 EfficientAD Small,验证时返回异常分数、区域及热图
🧠 独立模型管理 YOLO 模型由 SQLite 管理;Anomalib 模型按用户隔离注册,支持导入、下载和删除 ONNX 模型包
🖱️ 图片验证 YOLO 与 Anomalib 各有独立验证页;联合验证页提供联合识别、仅 Anomalib、仅 YOLO 三种模式
🔍 大图查看器 点击缩略图查看原图,支持缩放、拖动与翻页;YOLO 结果查看器还可切换原图
🎬 视频验证 YOLO 按标签汇总识别结果;Anomalib 逐帧统计异常并生成区域标注视频
⚡ 多硬件执行 YOLO 支持 CPU、NVIDIA CUDA / TensorRT;Anomalib ONNX 识别支持 CPU / CUDA,Tasks 与 API 复用 Server 核心逻辑
📊 实时性能 毫秒级耗时统计,批量验证与置信度分析

🏷️ Tasks Web 工作台

特性 说明
🏷️ 双模型工作台 YOLO 完成工程管理、标注、训练与验证;Anomalib 完成正常图上传、异常模型训练与验证
📤 上传不中断 上传任务由服务持有:切换页面、切回、甚至重新渲染都不会丢失进度,横幅可随时取消
🗂️ 每模型独立队列 每个模型各自保存验证文件队列、当前选中项与识别结果,刷新浏览器后仍可恢复
🎞️ 图片与视频验证 一次最多 100 个文件;视频后台逐帧识别、实时显示进度与预计剩余时间
📥 增量导入 YOLO ZIP 可一批批上传:同名类别复用、新类名追加、标注下标自动重映射到工程标签
🐍 Python 辅助 内置模型导出脚本,一键转换 PyTorch → ONNX
🖥️ WPF 调试工具 5 种识别模式可视化验证 + 数据统一标注工具

🏋️ 训练

特性 说明
🔢 默认 500 轮 训练弹窗可在 100–10000 轮间以 100 轮为步长调整;小数据集在 50 轮时只有几十次参数更新,模型学不到东西;Ultralytics 会按 patience 自动早停
🎯 默认不切验证集 小数据集再切掉 10% 会明显影响训练;需要客观指标时在训练配置里勾选「使用验证集(自动划分 10%)」
🩺 训练前体检 日志给出每类实例数、图片数、目标像素尺寸与验证集大小,并对"注定识别不到"的数据逐条告警
🔬 训练后自检 读取 results.csv 的 mAP;验证集过小时自动在训练集上复验,明确告知模型是否真的学到了东西
📥 权重下载命令 企业代理拦截 GitHub 时(curl 60),日志直接给出按系统生成的 curl 命令(自动带上代理与 CA 参数),下完即被复用
🔎 Anomalib 训练门禁 训练后导出 ONNX,检查与训练模型的一致性,并阻止正常图校准集误报率超过 5% 的模型注册

🚀 部署与运维

特性 说明
🌍 多平台发布 WPF 支持 Windows;Tasks/API 发布 Windows 与 Linux 包,并提供 Linux Docker 镜像
🛠️ FFmpeg 自检 上传视频即自检:Windows 弹窗选择(手填路径 / 静默下载安装),Linux 直接用 apt 全局安装,失败不影响图片流程
🔤 中文不再变方框 视频标注文字改用系统中文字体绘制;Linux 缺少中文字体时随 FFmpeg 一起自动安装
📦 开箱即用 CPU 与 CUDA/TensorRT 产品独立运行;核心库与执行提供程序也可作为 NuGet 依赖使用

🔒 安全与性能

特性 说明
🔒 明确安全边界 Tasks 使用 Cookie 登录与 CSRF 防护;API 按产品要求匿名,并提供限流、CORS 与安全响应头
🔐 Tasks 按用户隔离 工程、标注、模型、验证数据与文件按登录用户隔离,训练环境共享;API 模型使用独立服务账户
🔄 模型实例缓存 配置不变时复用模型实例,避免重复加载
🧵 异步任务处理 上传、训练调度与文件读写采用异步处理,耗时视频识别可查看进度并取消

📖 各项细节见下方对应章节:Tasks 工作台 · 视频与 FFmpeg · 配置文件 · 安全特性 · 性能优化

🎯 应用场景

场景 用途 推荐模型类型
🏭 工业质检 先定位可疑区域,再识别已知缺陷类型;也可进行异物识别、零件计数 Anomalib、检测、分割
🛒 零售分析 顾客行为追踪、货架商品检测 检测、分类
🛡️ 智能安防 异常行为监测、跌倒检测、区域入侵 姿态估计、检测
🚗 自动驾驶 道路目标检测、交通标志识别 定向检测、检测
🏥 医疗影像 病灶分割、细胞分类 分割、分类
📄 文档分析 旋转文本检测、表格识别 定向检测
🌐 边缘计算 x64/ARM64 CPU 或 NVIDIA Jetson 部署 CPU、CUDA

🏗️ 项目架构

VisualIdentity/
├── YoloDotNet/                    # 🧠 ONNX 模型解析、预处理与后处理
├── YoloDotNet.ExecutionProvider.Cpu/  # 🖥️ CPU 执行提供程序
├── YoloDotNet.ExecutionProvider.Cuda/ # 🎮 CUDA / TensorRT 执行提供程序
├── Snet.Yolo.Server/              # 🗄️ SQLite 数据访问、模型管理与推理服务
├── Snet.Yolo.Api.Shared/          # 🔗 共享 API 层(Shared Project:控制器 / 安全 / 图片处理)
├── Snet.Yolo.Api.Cpu/             # 🖥️ CPU API(HTTP 5157 · HTTPS 7257)
├── Snet.Yolo.Api.Cuda/            # 🎮 CUDA / TensorRT API(HTTP 5158 · HTTPS 7258)
├── Snet.Yolo.Tasks.Core/          # 🏷️ 标注配置、编辑、导出与训练领域逻辑
├── Snet.Yolo.Tasks.Shared/        # 🔗 Tasks 共享项目(Blazor 组件、服务与静态资源)
├── Snet.Yolo.Tasks.Cpu/           # 🖥️ CPU Tasks(HTTP 5151 · HTTPS 7351)
├── Snet.Yolo.Tasks.Cuda/          # 🎮 CUDA / TensorRT Tasks(HTTP 5152 · HTTPS 7352)
├── Snet.Yolo.Tool/                # 🛠️ WPF 桌面调试工具
├── Snet.Yolo.Test/                # 🧪 xUnit 回归与集成测试
├── Snet.Py/                       # 🐍 Python 模型导出脚本
├── docker/                        # 🐳 Tasks / API 的 CPU 与 CUDA 镜像定义
├── VisualIdentity.sln             # 🧩 解决方案入口
└── appsettings.json               # ⚙️ API 共用配置

🔄 数据流

客户端上传图片 → API 控制器(参数验证)→ 速率限制中间件
→ ManageOperate(数据库查询模型路径)→ IdentityOperate(加载模型 + 硬件加速)
→ YoloDotNet 推理(GPU / CPU)→ ResultHandler(结果转换)
→ ImageHandler(标注绘制 + 磁盘存储)→ 返回 JSON + 图片 URL

⚡ 快速开始

🧰 前置要求

1️⃣ 克隆仓库

git clone https://github.com/shunnet/VisualIdentity.git
cd VisualIdentity

🏷️ 使用 Tasks Web 工作台

# CPU 版本
dotnet run --project Snet.Yolo.Tasks.Cpu

浏览器访问 http://localhost:5151。首次启动会创建默认管理员 snet,默认密码为 123456。可在启动前通过 SNET_BOOTSTRAP_ADMIN_PASSWORD 覆盖密码;现有管理员无法登录时,也可设置该变量并重启,以同步管理员密码。

🐍 训练功能还需要本机可用的 Python。Tasks 会检测并创建共享虚拟环境,再按所选任务启动 Ultralytics 训练。

🖥️ 需要指定验证推理硬件时,改为启动对应项目:

项目 执行提供程序 适用平台
Snet.Yolo.Tasks.Cpu YoloDotNet.ExecutionProvider.Cpu 通用 CPU
Snet.Yolo.Tasks.Cuda YoloDotNet.ExecutionProvider.Cuda NVIDIA CUDA / TensorRT

💡 例如:dotnet run --project Snet.Yolo.Tasks.Cuda。CPU 与 CUDA 项目共同导入 Snet.Yolo.Tasks.Shared,仅执行提供程序不同;训练环境仍然共享。

2️⃣ 运行 CPU 版本 API

cd Snet.Yolo.Api.Cpu
dotnet run

🌐 浏览器访问 http://localhost:5157/swagger 查看 Swagger UI(仅 Development 环境)。

3️⃣ 上传模型并推理

# 1. 上传 ONNX 模型
curl -X POST http://localhost:5157/Operate/AddAsync \
  -F "file=@your_model.onnx" \
  -F "describe=我的检测模型" \
  -F "onnxType=ObjectDetection"

# 2. 快速推理(仅坐标 / 标签 / 置信度)
curl -X POST http://localhost:5157/Operate/IdentityAsync \
  -F "onnxIndex=1" -F "file=@test.jpg" \
  -F 'paramJson={"Confidence":0.2,"Iou":0.7}'

# 3. 完整推理(标注图 + 坐标 + 图片 URL)
curl -X POST http://localhost:5157/Operate/IdentityDrawAsync \
  -F "onnxIndex=1" -F "file=@test.jpg" \
  -F 'paramJson={"Confidence":0.2,"Iou":0.7}'

🏷️ Tasks Web 标注与训练工作台

🧩 Snet.Yolo.Tasks.Shared 提供解决方案内置 Blazor Web 工作台的共享实现,CPU 与 CUDA 项目复用同一套界面、业务服务与静态资源;CPU 环境使用 Snet.Yolo.Tasks.Cpu。工作台覆盖从数据准备到模型验证的完整流程:

  1. 🔐 登录后创建工程,选择检测、分割、分类、姿态估计或 OBB 任务模板。
  2. 🖼️ 导入图片并在浏览器中完成矩形、旋转框、多边形、关键点或分类标注。
  3. 📦 导出 YOLO 标签,或导出同时包含原图的 YOLO ZIP 数据集。
  4. ⚙️ 配置轮数、图像尺寸、基础模型与设备,实时查看训练阶段、指标和日志。
  5. 🚀 下载训练得到的 best.pt,或导出 ONNX 并直接进入验证页推理。

✏️ 图片多边形与曲线标注

手动多边形绘制时点击起点、双击或按 Enter 闭合。使用选择工具选中多边形后显示顶点/曲线操作按钮;方形把手拖动顶点,圆形把手拖动曲线控制点。删除顶点至少保留三个,相邻边重新连接为直线。Esc 取消拖动,Ctrl+Z / Ctrl+Shift+Z 撤销/重做。

保存的标注 JSON 在 value.snet_bezier 中保留百分比控制点,重新打开可以继续编辑。YOLO 分割标签与 COCO 导出自动将曲线细分为多边形(原图像素误差不超过 0.5px),不会修改原始标注;不识别该扩展字段的第三方 JSON 工具只会读取锚点。本功能仅用于图片,不包含视频跟踪。

🪄 SAM 点选辅助标注

模型、辅助标注开关和所选设备按登录用户保存在当前浏览器,刷新后自动恢复;原 GPU 不可用时恢复为 CPU。不保存提示点或未确认的预览。浏览器禁用本地存储时,这些偏好不能跨刷新保留。

运算设备:五种 SAM 模型均可选择 CPU 或单张 NVIDIA GPU。界面自动检测 GPU 编号、名称及显存,沿用训练配置的设备按钮与硬件卡片,可手动指定 GPU;默认 CPU。CPU 发行包仅开放 CPU,GPU 需 CUDA 发行包及兼容驱动、CUDA/cuDNN。选择 GPU 后初始化失败会明确报错,不静默降级为 CPU;部分不支持的 ONNX 算子仍可能由 CPU 执行。当前交互式单图推理不支持多 GPU 联合运算,因此不提供多选。切换设备会清除预览和图片编码,下次点选在所选设备创建会话;服务端仍最多驻留一套会话,多用户切换模型或设备会产生重新加载开销。

工具下方开启 SAM 辅助标注,选矩形、多边形或笔刷,点击物体生成预览;继续点击补充前景,按住 Shift 点击排除背景,最后点击「确认标注」。矩形采用物体外接框,多边形采用简化外轮廓,笔刷采用实心掩码。关闭 SAM 恢复手动工具。SAM 不是类别识别,也不保证一次点击就精确贴边;结果应人工检查。

工具下方可以自行选择 MobileSAM(默认) / SAM 2.1 Tiny / SAM ViT-B / SAM ViT-L / SAM ViT-H,界面同时显示文件体积和资源提示。由 Snet.Yolo.Server 直接执行 ONNX 推理,不经过 API,不需要 Python 环境。CPU/CUDA 宿主复用现有 ONNX 硬件配置;同一图片、同一模型复用编码,切图或换模型会清除未确认预览与页面编码,取消未完成请求。首次下载会查询上游,选择当前程序已验证目录中的最新兼容权重,锁定实际仓库提交并校验压缩包、ONNX 及外部权重的 SHA-256;失败可重新开启重试。服务端最多驻留一套模型会话,加载新模型前释放旧会话,避免多套同时占用内存/显存;多用户选择不同模型时切换会增加加载耗时。

版本与更新:开启 SAM 后显示已安装的提交版本,提供「检查更新」;存在兼容新权重时显示「更新模型」,更新成功后提供「回退上一版本」。已有安装不会自动覆盖。相同权重的新提交可锁定其最新提交;上游权重变化但未进入兼容目录时,只提示尚未验证,不自动使用。维护者需完成 ONNX 接口与效果验证、保留历史目录记录,并随程序发布更新兼容目录;“最新兼容”不是任意上游最新版,也不保证效果更好。当前每种模型有一个已验证权重版本,因此没有新兼容权重时不会显示更新按钮。查询上游失败时首次下载退回程序内推荐的固定版本;已有版本保持不变。

版本记录位于各模型目录的 active-model.json,记录当前与上一版本;手动更新下载到 .versions/<实际提交 SHA>/,通过完整性校验、所选 CPU/GPU 的编码/解码试运行后才原子切换记录。下载、验证或取消失败保留原版本;未激活的已下载文件作为重试缓存保留。旧文件不删除,供回退及其他页面已编码图片继续使用。更新是服务器共享操作,影响全部用户;发起更新的页面清空未确认预览与编码,其他页面已有图片编码继续绑定原解码器,新图片使用当前版本。保留上一版本与候选版本会额外占用磁盘空间;离线部署仍可按下方目录提供已验证文件或 ZIP。

模型 ONNX 文件合计 单图特征缓存 资源提示
MobileSAM 约 45 MB 约 4 MB 资源占用低,默认推荐,适合 CPU/低显存设备
SAM 2.1 Tiny 约 126 MB 约 16 MB 资源占用中等,建议 GPU,CPU 首次处理更慢
SAM ViT-B 约 376 MB 约 4 MB 权重及中间计算占用高,优先使用 GPU,CPU 首次编码较慢
SAM ViT-L 约 1251 MB 约 4 MB 更高内存/显存开销,建议 GPU,CPU 编码较慢
SAM ViT-H 约 2567 MB 约 4 MB 资源开销最高,建议资源充足的 GPU,低显存可能内存不足

文件体积和特征缓存不是整体内存/显存需求:运行时还有模型权重、中间计算和原图占用,实际依赖硬件、执行后端与图片尺寸。下载/解压还需要额外磁盘空间(Tiny 压缩包约 117 MB,ViT-B 约 349 MB,ViT-L 约 1162 MB,ViT-H 约 2384 MB)。ViT-H 的外部权重文件必须与编码器放在同一目录。更大不保证每张图更准确,请用实际图片比较。所有用户共享程序根目录下的 sam,不放进 train 或用户工程目录:

程序根目录/
└── sam/
    ├── mobile_sam_image_encoder.onnx
    ├── sam_mask_decoder_multi.onnx
    ├── sam2.1-tiny/
    │   ├── sam2.1_hiera_tiny.encoder.onnx
    │   └── sam2.1_hiera_tiny.decoder.onnx
    ├── sam-vit-b/
    │   ├── sam_vit_b_01ec64.encoder.onnx
    │   └── sam_vit_b_01ec64.decoder.onnx
    ├── sam-vit-l/
    │   ├── sam_vit_l_0b3195.encoder.onnx
    │   └── sam_vit_l_0b3195.decoder.onnx
    └── sam-vit-h/
        ├── sam_vit_h_4b8939.encoder.onnx
        ├── sam_vit_h_4b8939.encoder_data.bin
        └── sam_vit_h_4b8939.decoder.onnx

离线部署可从 Acly/MobileSAM 固定版本 下载这两个同名文件后复制到 sam(目录需有写权限);应用仍会校验,文件不匹配时保留原文件并提示处理。代理网络必须配好受信任证书,不关闭 TLS 校验。模型源自 MobileSAM,ONNX 转换版本由 Acly 提供;分发模型时遵循其上游许可。

新增模型采用 SAM 2.1 Tiny 固定权重包 和 SAM ViT-B 固定权重包,由 vietanhdev 提供 ONNX 导出,原始模型为 Meta SAM/SAM 2.1。离线时可将 ZIP 放入对应子目录,应用校验后只解压固定名称的 ONNX 和所需外部权重;也可按上述目录手动放置已解压文件。不会执行 ZIP 中的配置或代码。离线提供的 ZIP 保留;本次自动下载的 ZIP 成功解压后清理。 ViT-L 与 ViT-H 分别使用同一固定仓库版本中的 sam_vit_l_0b3195.zip 与 sam_vit_h_4b8939.zip。ViT-H 三个模型文件均须完整,启动时逐一校验;大模型单次下载超时为 30 分钟,可取消。

图片最多 2400 万像素,推理最长边 1024;极小缺陷可能需要手动修正。矩形、多边形可继续编辑;SAM 笔刷支持选择、删除、撤销/重做和保存回显,不支持整体拖移或修改原掩码。笔刷 RLE 保留孔洞,YOLO 单多边形标签仅导出外轮廓,不表达孔洞。

🔎 业务流程:先找哪里异常,再判断是什么缺陷

工业现场可以把 Anomalib 和 YOLO 当成分工不同的两位检查员:先用正常图片训练 Anomalib,让它在新图片中标出与正常状态不同的可疑区域,回答「异常在哪里」;再用已标注缺陷类别的图片训练 YOLO,在同一图片中识别划痕、裂纹、异物等已知缺陷,回答「这是什么」。把位置和类别结合起来,便于复核、记录和处理。

Anomalib 不需要预先收集每一种缺陷样本,但发现异常不等于知道缺陷名称;YOLO 能给出训练过的类别,但不保证识别从未学过的缺陷。在「联合验证」页,Anomalib 先定位异常;如果图像被判为异常,YOLO 对原图识别一次,再把检测框与异常区域按位置关联。YOLO 没有匹配到的异常仍显示为「类型未识别」,不会改判正常。该级联目前用于图片;视频仍使用各自的独立验证流程。

联合验证的模型设置可调整识别参数:Anomalib 提供区域异常阈值和最小异常面积;YOLO 参数与独立验证页一致,目标检测显示置信度和 IoU,实例分割额外显示像素置信度。页面将当前参数传给 Snet.Yolo.Server,修改参数后需重新识别。

联合验证支持多选上传图片(最多保留 500 张),通过与 YOLO 验证页一致的缩略图列表切换图片。点击图片自动识别,默认联合识别;执行「仅 Anomalib」或「仅 YOLO」后,后续点击沿用该模式。每张图片独立保留结果、热力图与耗时,刷新可恢复图片列表及当前选中项;修改模型或参数会清除全部旧结果,避免不同配置的结果混用。

Anomalib 独立验证也提供区域过滤参数(初始区域阈值 0.80、最小面积 4 个异常图像素,非原图像素)。区域异常阈值使用数值输入,联合验证的模型设置区支持滚动查看全部参数。提高参数可减少零碎框,但可能漏掉细小缺陷;它们不改变模型的整图正常/异常判断,也不改变训练注册的 5% 误报门禁。Anomalib 与联合验证按登录用户保留已上传文件、模型选择、已完成结果、日志及参数,刷新页面可恢复;识别中的任务在离开页面时取消,不自动续跑。状态保存在应用内存中,应用重启后清空;移除文件才删除对应源文件,继续上传不会删除之前的图片。

🧩 Anomalib 异常区域(第一阶段)

在侧栏进入「Anomalib 项目」,新建独立工程并上传至少 10 张正常图片,无需画框或提供缺陷标签。工程详情页支持点击缩略图查看原图、翻页浏览(每页 150 张),并显示训练阶段与状态。训练页沿用 YOLO 的进度、日志和右侧硬件资源布局;点击「开始训练」后,在弹窗中选择 PaDiM(默认)或 EfficientAD Small,并配置输入尺寸和设备。选择模型时下方会显示该算法的特点。YOLO 工程详情页也提供「模型训练」入口。Tasks 首次运行会建立独立的 train/anomalib/.env,不改动 YOLO 训练环境;训练完成后导出 ONNX,并用本次训练的内存模型与 ONNX 比较校准图片结果(不反序列化 .pt)。只有一致性与正常图误报门禁都通过的模型才会注册并出现在「Anomalib 验证」。

🧠 模型与输入尺寸:PaDiM 按画面位置建立正常特征分布,适合相对固定的机位;EfficientAD Small 使用教师—学生网络,侧重快速推理。训练弹窗不再提供 PatchCore 选项,其 ONNX 导出仍属实验路径。输入尺寸是训练和推理时缩放后的正方形尺寸,新配置默认 640 × 640,可设为 128–2048 之间的 32 的倍数;修改后需重新训练。增大尺寸能保留更多小目标细节,但会增加资源开销,也不保证减少误检。

🖼️ 验证与模型文件:验证页采用与 YOLO 相同的模型、结果、文件和预览分区,支持批量图片与视频。图片显示异常热图和原图坐标区域;视频需 FFmpeg/FFprobe,逐帧识别并生成可播放的区域标注视频,可查看进度并取消(单文件不超过 100 MiB、视频不超过 10000 帧)。模型可从列表下载或删除;下载得到包含 model.onnx 和 model.manifest.json 的 ZIP,添加模型时可在弹窗中填写名称、描述、类型并上传这种 ZIP。Anomalib 四个页面支持中英文切换,第三方训练原始日志保持原文。

⚠️ 注册前会检查训练模型与 ONNX 的一致性,并要求留出的正常图片校准集误报率不超过 5%;超过阈值则不注册。通过门禁仍不代表缺陷检出率合格,应使用独立的正常图和已知异常图检查误报、漏检。尤其使用 PaDiM 时,应尽量保持机位和检测区域稳定。不通过门禁的模型不会提供推理。实际训练需本机 Python 3 和模型依赖可用,首次安装可能需要联网。

EfficientAD 首次训练还会下载预训练教师权重和 ImageNette 数据。若在 WSL 中遇到 CERTIFICATE_VERIFY_FAILED,应检查 WSL 内的代理和 CA 信任(Windows 的证书信任不会自动解决 WSL 内 Python 的证书错误);可将 Training:CaBundle 配置为 WSL 内可读取的 PEM 证书包路径,重启服务后 Anomalib 训练子进程会继承该配置。不要通过关闭 TLS 证书校验解决。

📤 上传中心

🧭 所有上传入口(工程图片、分类图片、YOLO ZIP、验证图片/视频、ONNX 模型)共用一套常驻上传通道:

特性 说明
🔄 切页不中断 上传任务由服务持有,切换页面、切回、页面重绘都不会中断,也不会丢进度
📊 进度可见 横幅显示当前文件名、字节数、百分比与「已完成 / 总数」,完成后自动收起
⏹️ 可取消 取消立即生效:正在复制的文件会中断(流式读写带取消标记),已完成的部分自动清理
🧹 失败可续 单个文件失败只提示该文件,不影响同批次其它文件

🖼️ 验证页

📤 一次最多上传 100 个图片或视频;每个模型各有一份独立的文件列表与识别结果,刷新浏览器后仍可恢复:

交互 说明
🖱️ 点击图片 载入后自动执行识别,省掉「选图 → 点识别」两步
🎬 视频 解码耗时较长,仍由「识别」按钮触发;状态条实时显示阶段、帧进度与预计剩余时间
⏹️ 随时取消 排队中的视频任务会被跳过,执行中的会中断抽帧/逐帧推理/编码(并结束 ffmpeg 进程)
🔍 双击大图 打开查看器:滚轮以光标为锚点缩放、按住拖动、双击或按钮还原、顶部「原图」勾选切换原图/标注图、Esc 或点窗外关闭
📋 结果聚合 视频按标签汇总为「平均置信度 + 全片识别次数」;照片保持逐目标显示坐标

📌 验证数据(文件队列、选中项、识别结果)仅保留在当前应用进程内,正常关闭或重启 Tasks 后会清空,不写入业务数据库。

✏️ 编辑标签的同步语义(标签配置 = 唯一数据源)

平台的标签配置(工程里的 LabelConfigXml)是唯一权威数据源:标注画布、区域列表、工具栏、统计、导出、训练类表全部在读取时从它派生,所以结构上不会出现"某处还记着旧标签"的漂移。删除/改名这类存量标注上的改动则在保存时一次性收敛到所有已有标注:

操作 行为
✏️ 改名 所有引用该标签的标注框都显示新名字,导出/训练用的类名一起变
🎨 改色 颜色只存在于标签配置里(标注框只记名字),所以标注页、区域列表、画布全部即时生效
🗑️ 删除标签 该标签的所有标注框一并删除(画布不再显示、统计不再计数、导出也不会静默丢数据),并且不会保留位置:后面的标签下标整体前移
🧾 下标变化提示 删除确认框会明确提示"其余标签的下标会前移";类别顺序变化会影响导出与训练的类名顺序
🔁 重新导入不受影响 YOLO ZIP 导入按类名匹配(同名的复用、新的追加),包里的 id 顺序随便排,所以下标前移不会让旧数据错位

💡 想让类别保持稠密、没有空类别:直接删除用不到的标签即可;工程外若有按下标对齐的快照(如旧训练记录),删完后按新顺序重新导出一次。

🖼️ 验证页大图预览(原图不压缩)

验证页上传的图片原样保存(不做任何加工,上传就是你原本的速度)。为了显示不卡顿,服务端会为图片生成一张小预览:

环节 行为
⬆️ 上传 原图直接落盘,服务端零加工 ✓
🔥 后台预热 上传成功后后台悄悄生成预览(约 1~3 秒/张,不阻塞上传、失败不影响识别)✓
🖼️ 页面显示 文件列表、主视图、画布叠加全部用预览(75 MB 的 BMP → 约 370 KB),浏览器不再解码 5120×5120 大位图 ✓
🔍 双击查看器 直接用原图(要看就是看清细节,放大后依然清晰);原图万一取不到才退回预览 ✓
🗑️ 删除 原图与预览一起删除;应用停止时会清理本进程创建的验证文件 ✓

💡 为什么不能"只靠 CSS 缩小显示":浏览器必须先解码整张位图才会缩小 —— 5120×5120 单张就要约 100 MB 内存,列表里几张就够把主线程卡住(心跳发不出去还会被判定断线)。预览把解码成本从 100 MB 降到几 MB,这才是"丝滑"的关键。

配置(appsettings.json) 默认 说明
Validation:Preview:Enabled true 关掉就直接显示原图(不生成预览)
Validation:Preview:MaxEdge 1600 预览最长边
Validation:Preview:TargetBytes 409600 预览体积上限(400 KiB)
Validation:Preview:StartQuality / MinQuality 82 / 60 预览 JPEG 质量区间

🔗 列表状态写进地址栏:项目详情的页码、搜索词、展开的类别文件夹(?page=3&q=…&folder=…)与用户管理的搜索词(?q=…)刷新后都会恢复,链接也能直接分享;标注页当前是第几张图本来就在路由里(/labeling/{工程}/{序号})。 📌 覆盖范围:所有"看一眼"的位置都用预览(验证页列表与主视图、项目详情的图片表格与文件夹封面、分类图片网格);标注页画布与查看器大图仍加载原图(标注需要像素级精度)。识别本身始终用原图。 ⏳ 加载反馈:验证页查看器、标注页首次打开与「上一页/下一页」在解码大图期间都会显示加载动画(标注页还会预加载相邻图片,切页通常瞬间完成)。 ⚠️ 识别框的 Position 坐标是原图像素空间(例如 5120),而画布放的是预览图(1600):前端会按原图尺寸把框等比缩放到画布上,所以叠加框位置准确;页面同时把原图地址作为兜底,预览取不到时会自动退回原图继续绘制。

📥 YOLO ZIP 导入(可反复增量上传)

支持两种来源,都上传到检测工程的「导入 YOLO ZIP」:

来源 包内结构
本应用导出 classes.txt + images/ + labels/
Roboflow / Ultralytics 导出(YOLOv5 / v8 / 11 / 26 等) data.yaml(names、nc)+ train/valid/test 各自的 images/ 与 labels/

包内规则会逐个校验,不符合直接拒绝:

要求 说明
📄 类别表 classes.txt(每行一个类名,或 索引 名称,索引必须从 0 连续)或 data.yaml 的 names(行内列表 ['a', 'b']、块列表 - a、映射 {0: a} 都认;写了 nc 会与类别数交叉校验)。两者同时存在时以 classes.txt 为准
🖼️ 图片 任意层级下 images/ 目录里的 jpg / jpeg / png / gif / webp / bmp
🏷️ 标注 同级 labels/ 下的同名 .txt,每行 类别 cx cy w h(归一化 0~1,空文件 = 纯背景图)。图片缺少对应 .txt 时按"无目标"导入——YOLO 生态(含 Roboflow)就是用"没有 .txt"表示无标注图片;反过来"有标注却没有图片"仍然是错误
📏 体积 单图 ≤ 100 MiB、图片数 ≤ 100,000、单次上传 ≤ 16 GiB
🔁 重复条目 同一份 data.yaml 被重复写进包里(Roboflow 就会写三份)只要内容一致就接受;图片/标注路径重复一律拒绝

💾 磁盘预留:ZIP 本体先落到系统临时目录,再逐张解到工程目录,请预留约两倍包大小的空间;空间不够会在开始上传前直接提示,而不是传到一半才失败。

导入是增量的:可以一批批往同一个工程里传,标注持续累加:

情况 平台行为
包里的类名与工程已有标签同名(忽略大小写) 复用已有标签,连原有写法都保留,不新增
包里出现新类名 追加为新标签,并分配不与现有颜色重复的颜色
标注里的类别下标 按「本包下标 → 工程标签名」重映射后写入,包的 id 顺序可以任意排列
重复导入同一批 标签不会重复(幂等);但图片会重复,同一批请不要重复上传
工程自带模板标签(如 Airplane / Car) 不会被删除;用不到就在标签编辑器里删掉,免得训练时多出零样本类别

💡 多批上传时类名保持一致是唯一需要人工守住的事——名字就是类别身份("虫茧" ≠ "茧")。

🏋️ 训练

特性 说明
🔢 默认 500 轮 训练弹窗可在 100–10000 轮间以 100 轮为步长调整;小数据集在 50 轮时只有几十次参数更新,模型学不到东西;Ultralytics 会按 patience 自动早停
🎯 默认不切验证集 小数据集再切掉 10% 会明显影响训练;需要客观指标时在训练配置里勾选「使用验证集」
🩺 训练前体检 日志直接给出每类实例数、图片数、目标像素尺寸、验证集大小,并对「注定识别不到」的数据逐条告警
🔬 训练后自检 读取 results.csv 的 mAP;验证集过小时自动在训练集上按界面默认置信度复验,明确告知模型是否真的学到了东西
📥 权重下载命令 检测到证书/下载类失败时,按当前系统生成可直接复制的 curl 命令(自动带上 Training:Proxy / Training:CaBundle),下完即被自动复用

🐍 训练环境(Python + venv + torch + ultralytics)由 Tasks 自动检测与搭建,代理与 CA 通过 Training 配置节统一控制。GPU 训练不会只判断“是否安装 torch”,还会核验 torch.version.cuda 与 torch.cuda.is_available():Pascal / Volta / Turing 使用兼容面更广的 CUDA 11.8 wheel,Ampere 及更新架构在驱动满足 CUDA 12 要求时使用 CUDA 12.8 wheel;旧驱动自动选择兼容通道,无法安全使用 CUDA 的旧卡明确回退 CPU。

🎮 YOLO 与 Anomalib 训练弹窗会列出检测到的全部 NVIDIA GPU,可通过设备按钮选择 CPU、自动、一张或多张 GPU;训练页按设备分别显示 GPU 利用率与显存。YOLO 多卡使用 Ultralytics 分布式训练;Anomalib 的 EfficientAD 可选择多卡,PaDiM 只能选择单卡。Windows 原生 PyTorch 的多卡训练不受当前方案支持,请在 Linux / WSL2 使用;多卡数据并行不会把各卡显存合并成一块,单卡显存不足仍可能报错。开始训练前会校验所选设备是否对 PyTorch 可见,Anomalib 仍需通过 ONNX 一致性与正常图误报门禁才会注册模型。

📦 YOLO 训练与 AMP(自动混合精度)自检共用程序目录下的 train/yolo/weights 缓存。训练前通过 Ultralytics 设置接口配置权重路径,配置文件隔离在当前工程的 ultralytics-config 目录,不改用户全局设置;多卡子进程继承同一配置。将 yolo26n.pt 放进缓存后,AMP 自检可直接复用,仍保留自检;该自检文件尚未缓存时仍可能需要下载,即使训练选择了其他型号。

🎬 视频验证的 FFmpeg 部署

🎥 视频解码需要 ffmpeg 和 ffprobe(图片验证不依赖它们)。上传视频时会自动自检,缺失时:

平台 行为
🪟 Windows 弹窗让用户选择:手动指定路径(填 ffmpeg.exe 或所在目录)或 静默下载安装(从 GyanD/codexffmpeg 取最新版,解压到程序目录 tools/ffmpeg/win-<arch>/),并在页面上显示下载/解压进度
🐧 Linux(Ubuntu/Debian) 不弹窗,直接 sudo -n apt-get install -y ffmpeg 全局安装并显示进度;索引过期会自动 apt-get update 后重试;失败才弹窗(附手动指定路径兜底)
🍎 macOS / 其它 弹窗手动指定路径(或自行 brew install ffmpeg 后自动发现)

📌 安装完成后路径会记入 tools/media-tools.json,视频解析直接复用;中文字体缺失时会随同一次流程安装(fonts-noto-cjk),保证视频标注里的中文不会画成方框。下载或安装失败只做顶部提示,不影响图片上传与识别。

🔍 自动查找顺序(也支持完全手动):

1️⃣ MediaTools:FFmpegPath / MediaTools:FFprobePath 配置。 2️⃣ SNET_FFMPEG_PATH / SNET_FFPROBE_PATH 环境变量。 3️⃣ 安装记录 tools/media-tools.json(手动指定或自动安装后写入)。 4️⃣ 应用目录下的 tools/ffmpeg/<RID>/,例如 tools/ffmpeg/win-x64/ 或 tools/ffmpeg/linux-x64/。 5️⃣ 系统 PATH 及 Windows/Linux/macOS 常见安装目录。

🪟 手动安装(Windows 10/11)

# 🪄 winget(推荐)
winget install --id Gyan.FFmpeg --exact

# 🍫 或 Chocolatey
choco install ffmpeg

# ✅ 新开一个终端后验证两个命令
ffmpeg -version
ffprobe -version

💡 Windows Server 没有 winget 时,可从 FFmpeg 官方下载页 选择 Windows 构建,解压后将 bin 目录加入 PATH,或将该目录填入 MediaTools:FFmpegPath。

🐧 手动安装(Ubuntu / Debian)

sudo apt update
sudo apt install -y ffmpeg
# 🔤 中文字体(视频标注里的中文需要)
sudo apt install -y fonts-noto-cjk
ffmpeg -version
ffprobe -version

📦 ffprobe 由同一个 ffmpeg 软件包提供,不需要另外安装。Tasks 会自动完成上面两步,这里仅作为离线/无 sudo 权限时的兜底。

🧩 手动安装(其他 Linux 发行版)

# 🎩 Fedora
sudo dnf install -y ffmpeg-free

# 🏔️ Arch Linux
sudo pacman -S ffmpeg

# 🏔️ Alpine Linux
sudo apk add ffmpeg

ffmpeg -version
ffprobe -version

💡 如果发行版软件源没有 FFmpeg,可将两个可执行文件放入发布目录的 tools/ffmpeg/linux-x64/ 或 tools/ffmpeg/linux-arm64/,然后执行 chmod +x ffmpeg ffprobe;也可以通过 SNET_FFMPEG_PATH 与 SNET_FFPROBE_PATH 显式指定路径。

🍎 手动安装(macOS)

brew install ffmpeg
ffmpeg -version
ffprobe -version

🔧 显式配置路径

{
  "MediaTools": {
    "FFmpegPath": "/opt/ffmpeg/bin/ffmpeg",
    "FFprobePath": "/opt/ffmpeg/bin/ffprobe",
    "InstallDirectory": "/opt/ffmpeg",
    "DiscoverInstalledTools": true
  }
}

📌 路径也可填包含这两个文件的目录(含解压常见的 bin/ 子目录)。InstallDirectory 指定自动安装位置(默认程序目录下 tools/ffmpeg);DiscoverInstalledTools 设为 false 时只认配置、安装记录与安装目录,便于固定使用某一套工具。如果工具缺失或显式路径错误,视频任务会立即停止并显示当前操作系统、CPU 架构和可用的配置方式,不会持续转圈。

🗄️ 工作台使用 SQLite 保存工程、用户和标注元数据。工程、标注任务、验证模型及数据库查询均按登录用户隔离;上传图片保存到 wwwroot/data/uploads/<用户名>/,ONNX 模型保存到 wwwroot/onnxs/<用户名>/,训练数据和产物分别保存到 train/yolo/<用户名>/<项目>/ 和 train/anomalib/<用户名>/<项目>/,共享环境分别为 train/yolo/.env 和 train/anomalib/.env。不兼容或自动迁移旧训练目录,旧文件不会删除;YOLO 权重缓存和状态分别位于 train/yolo/weights/ 和 train/yolo/statuses/。升级前已有的无归属数据自动归入 snet。删除任务或工程时会同步清理当前用户的对应文件。认证采用服务端 Cookie,会话页面、上传文件、模型下载和训练 Hub 均要求登录,普通用户不显示且不能访问用户管理页。

训练目录结构(<项目> 使用工程标识;各算法环境跨用户共享,工程数据按用户隔离):

train/
├── yolo/
│   ├── .env/
│   ├── weights/
│   ├── statuses/
│   └── <用户名>/<项目>/
└── anomalib/
    ├── .env/
    ├── scripts/
    └── <用户名>/<项目>/

与 .env、weights、statuses、scripts 等共享目录同名的用户会使用安全映射目录,避免覆盖共享文件。train/cuda-runtime/ 仍是验证模块共用的 CUDA 运行库目录,不属于某个训练算法。

🖥️ 界面展示

📦 NuGet 安装

💡 在您自己的 .NET 项目中使用 VisualIdentity 核心库:

# 核心推理库(必装)
dotnet add package Snet.Yolo.Server

# 按部署硬件选择执行提供程序
dotnet add package YoloDotNet.ExecutionProvider.Cpu      # 🖥️ 通用 CPU
dotnet add package YoloDotNet.ExecutionProvider.Cuda     # 🎮 NVIDIA GPU + TensorRT

💡 C# 调用示例

using SkiaSharp;
using Snet.Model.data;
using Snet.Yolo.Server;
using Snet.Yolo.Server.handler;
using Snet.Yolo.Server.models.data;
using Snet.Yolo.Server.models.@enum;
using YoloDotNet.ExecutionProvider.Cpu;
using YoloDotNet.Extensions;
using YoloDotNet.Models;

// 创建推理实例(自动缓存,配置不变时复用)
var identity = IdentityOperate.Instance(new IdentityData
{
    Hardware = new CpuExecutionProvider("/path/to/model.onnx"),
    IdentifyType = OnnxType.ObjectDetection,
    SN = "my-detector"
});

using SKImage image = SKImage.FromEncodedData("/path/to/image.jpg");

// 执行推理
OperateResult result = await identity.RunAsync(new ObjectDetectionData
{
    Confidence = 0.23,  // 置信度阈值
    Iou = 0.7,          // 交并比阈值
    File = image.Encode().ToArray()
});

// 获取结果并绘制标注框
var detections = result.GetObjectDetectionResult()?.ToObjectDetection();
if (detections is { Count: > 0 })
{
    foreach (var d in detections)
        Console.WriteLine($"{d.Label.Name}: {d.Confidence:P1} @ {d.BoundingBox}");

    using SKBitmap annotated = image.Draw(detections);
    // 保存或显示 annotated...
}

identity.Dispose(); // 释放 GPU 资源

🔌 API 接口文档

⚠️ API 按当前产品要求保持匿名访问,不启用登录授权。请仅部署在可信网络,或在反向代理/API 网关上增加访问控制;限流与 CORS 不能替代身份认证。

📋 模型管理

方法 路径 说明 认证
POST /Operate/AddAsync 上传 ONNX 模型文件 无(建议置于受信网络或认证网关后)
POST /Operate/UpdateAsync 修改模型描述或类型 无(建议置于受信网络或认证网关后)
POST /Operate/DeleteAsync 删除模型(可选删除文件) 无(建议置于受信网络或认证网关后)
GET /Operate/QueryAsync?index=1 查询指定模型 无
GET /Operate/QueryAllAsync 查询全部模型 无

🧠 推理接口

方法 路径 说明 返回内容
POST /Operate/IdentityAsync 🚀 快速推理 仅坐标 / 标签 / 置信度
POST /Operate/IdentityDrawAsync 🎨 完整推理 坐标 + 标注图 URL + 原图 URL

📌 推理接口为 POST multipart/form-data 提交(onnxIndex、file、paramJson 均为表单字段),以下额外参数同样以表单字段传入:

硬件版本 额外字段
🎮 CUDA gpuid(GPU ID)、trtConfig(TensorRT 配置)

🧩 Anomalib 模型与识别

Anomalib 与 YOLO 模型分别管理。模型包必须是包含 model.onnx 和 model.manifest.json 的 ZIP;导入时会验证清单、SHA-256 及 ONNX 输入输出契约。API 模型归属固定服务账户 snet,存放于 API 自己的 anomalib-api/<username>/<project>/ 目录,不会读取 TASKS 已登录用户的模型。TASKS 的 Anomalib 验证页仍直接调用 Snet.Yolo.Server,不绕行 HTTP API。

方法 路径 说明
GET /api/anomalib/models 列出 API 账户的模型
GET /api/anomalib/models/{projectId}/{runId} 查看模型名称、描述、类型和注册时间
POST /api/anomalib/models multipart/form-data:file(ZIP)、name、description、modelKind(Padim、EfficientAdSmall 或 PatchcoreExperimental)
PUT /api/anomalib/models/{projectId}/{runId} JSON:name、description;算法类型与模型清单绑定,不允许修改
GET /api/anomalib/models/{projectId}/{runId}/download 下载 ONNX 与清单 ZIP
DELETE /api/anomalib/models/{projectId}/{runId} 删除已注册模型
POST /api/anomalib/models/{projectId}/{runId}/identify multipart/form-data:file(图片)、可选 includeHeatmap;返回整图分数、异常判定、原图坐标区域、单张推理耗时和可选热图

导入包上限为 512 MiB;识别图片受 ConfigModel:MaxImageBytes(默认 100 MiB)限制。Anomalib 在 CPU 版 API 使用 CPU ONNX Runtime,在 CUDA 版 API 使用 CUDA;它不使用 YOLO 的 TensorRT 参数。

🖼️ 历史图片

方法 路径 说明
GET /Operate/GetOriginalImage?name=xxx&type=ObjectDetection&date=yyyy-MM-dd 获取原始图片(日期可选,省略时查找最近记录)
GET /Operate/GetMarkImage?name=xxx&type=ObjectDetection&date=yyyy-MM-dd 获取标注图片(日期可选)
GET /Operate/GetImageDetails?name=xxx&type=ObjectDetection&date=yyyy-MM-dd 完整详情(原图 + 标注 + 坐标 JSON;日期可选)

🏥 健康检查

方法 路径 说明
GET /health 健康检查(返回 {"Status":"Healthy","Timestamp":"..."})

🧾 paramJson 参数格式

识别类型 JSON 格式
对象检测 {"Confidence":0.2,"Iou":0.7}
定向检测 {"Confidence":0.2,"Iou":0.7}
图像分类 {"Classes":1}
姿态估计 {"Confidence":0.2,"Iou":0.7}
实例分割 {"Confidence":0.2,"Iou":0.7,"PixelConfidence":0.65}

⚙️ 配置文件

⚙️ API 根目录 appsettings.json

{
  "AllowedOrigins": [],           // 🔒 CORS 白名单,空数组 = 拒绝所有跨域
  "RateLimit": {
    "PermitLimit": 120,           // ⏱️ 每分钟允许的请求数
    "WindowMinutes": 1,           // ⏱️ 时间窗口(分钟)
    "QueueLimit": 20              // ⏱️ 超出后的最大排队数
  },
  "ConfigModel": {
    "NameFormat": "yyyyMMddHHmmssffffff",              // 🏷️ 文件名时间格式
    "OriginalImageNamingFormat": "{0}-Original.jpeg",  // 🖼️ 原图命名
    "ResultImageNamingFormat": "{0}-Result.jpeg",      // 🎨 标注图命名
    "DetailsNamingFormat": "{0}-Details.ini",          // 📄 详情文件命名
    "RetentionDays": 30,                              // 🗑️ 历史数据保留天数
    "MaxImageBytes": 104857600,                       // 🖼️ 单张推理图片上限(默认 100 MiB)
    "MaxModelBytes": 1073741824                       // 🧠 单个 ONNX 模型上限(默认 1 GiB)
  }
}

Tasks 使用 Snet.Yolo.Tasks.Shared/appsettings.json。训练代理位于 Training:Proxy 与 Training:CaBundle;媒体工具可通过 MediaTools:FFmpegPath、MediaTools:FFprobePath、MediaTools:InstallDirectory 和 MediaTools:DiscoverInstalledTools 配置,也可使用 SNET_FFMPEG_PATH / SNET_FFPROBE_PATH 环境变量。

💡 企业网络里配好训练代理与 CA 后重启,训练日志给出的权重下载命令会自动带上 --cacert / -x。

🌱 环境变量支持

变量 说明 默认值
ASPNETCORE_ENVIRONMENT 运行环境(Development / Production) Production
ASPNETCORE_URLS 服务监听地址 http://localhost:5157
SNET_BOOTSTRAP_ADMIN_PASSWORD Tasks 的 snet 管理员口令;设置时会在启动阶段覆盖默认密码并同步现有管理员 123456

⚠️ Swagger UI 仅在 Development 环境下启用,生产环境自动关闭。

🧠 支持的任务

分类 (Classification) 检测 (Detection) OBB 定向检测 分割 (Segmentation) 姿态估计 (Pose)
🔖 整图分类 📦 边界框定位 🔄 旋转框定位 🎭 像素级分割 🦴 关键点检测
输出标签+置信度 输出框+标签+置信度 输出旋转框+角度 输出遮罩+框+标签 输出骨骼点+框

📌 Tasks、HTTP API 与 WPF 当前公开以上五类任务。底层 YoloDotNet 还包含 YOLO26 语义分割和单目深度估计模块,但尚未通过 Snet.Yolo.Server.OnnxType 暴露为产品入口。

🦴 姿态估计 — 内置跌倒检测

🚨 YoloPoseViewModel 集成实时跌倒检测算法(FallDetector),基于 17 个人体关键点进行多维度分析:

检测维度 判定标准 可配置
📏 身体高度 鼻-踝距离 < 50% 图像高度 FlatHeightRatio
📐 身体倾角 肩-髋连线 < 70° AngleThreshold
↔️ 躯干水平度 肩髋 Y 差值 < 10% 图像高度 TorsoHorizontalThresholdRatio
📍 近地距离 平均关键点 Y > 60% 图像高度 GroundProximityRatio
✅ 综合判定 满足 ≥ 2 项即判定跌倒 FallScoreThreshold

✅ 支持的 YOLO 模型系列

✅ 当前仓库的 YoloDotNet 解析器包含以下模型系列和任务模块。具体 ONNX 文件仍须使用匹配的 Ultralytics 导出方式与输出布局;“支持”不代表任意第三方修改图都无需验证:

分类 (Classification) 检测 (Detection) 分割 (Segmentation) 姿态估计 (Pose) OBB 定向检测
YOLOv8-cls YOLOv5u YOLOv8-seg YOLOv8-pose YOLOv8-obb
YOLOv11-cls YOLOv8 YOLOv11-seg YOLOv11-pose YOLOv11-obb
YOLOv12-cls YOLOv9 YOLOv12-seg YOLOv12-pose YOLOv12-obb
YOLOv26-cls YOLOv10 YOLOv26-seg YOLOv26-pose YOLOv26-obb
YOLOv11
YOLOv12
YOLOv26
YOLO-World (v2)
YOLO-E
RT-DETR

🖥️ 执行提供者

Provider Windows Linux Docker 适用场景
🖥️ CPU ✅ ✅ ✅ 通用推理、x64/ARM64 环境
🎮 CUDA / TensorRT ✅ ✅ ✅ NVIDIA GPU 加速

📌 当前产品项目只提供 CPU 与 CUDA/TensorRT 两种执行路径;CUDA Tasks 仅发布 GPU 版 ONNX Runtime,并在 CUDA 不可用时复用其中内置的 CPU 执行路径,避免两套原生运行库互相覆盖。

当前 CUDA 执行提供程序固定使用 Microsoft.ML.OnnxRuntime.Gpu 1.23.2,作为现有 CUDA 12.8 / cuDNN 9 部署及较早 NVIDIA 显卡环境的兼容基线;这不表示该版本保证支持所有旧显卡。若较新的显卡无法使用 CUDA 推理,请将 YoloDotNet.ExecutionProvider.Cuda 中的 Microsoft.ML.OnnxRuntime.Gpu 升级到适配该显卡的最新稳定版本,并同步检查 Snet.Yolo.Server 的 ONNX Runtime Managed 依赖、驱动、CUDA/cuDNN 版本及项目的 CUDA 运行库准备逻辑,重新构建和发布。只升级 NuGet 包而保留不匹配的 CUDA 运行库,仍可能初始化失败;以 ONNX Runtime CUDA 兼容表 为准。

🎮 CUDA Tasks 在每次开始识别前确认当前构建与 GPU 环境。Windows / Linux x64 缺少 CUDA 12 与 cuDNN 9 时,程序通过 NVIDIA 官方 pip wheel 安装到应用私有目录 train/cuda-runtime/,不会修改系统驱动、PATH 或 LD_LIBRARY_PATH;按钮在准备期间显示进度并禁止重复点击。系统驱动仍由管理员维护:Windows 使用 NVIDIA 官方驱动,Ubuntu/Debian、Fedora/RHEL、SUSE、Arch 使用各发行版对应的 NVIDIA 驱动仓库;WSL 只更新 Windows 宿主驱动与 wsl --update,不要在 WSL 内安装 Linux 显卡驱动;容器还需要 NVIDIA Container Toolkit。macOS 不支持 CUDA,使用 CPU 或 MPS/CoreML 构建。详见 ONNX Runtime CUDA 要求、NVIDIA CUDA Windows 安装 与 CUDA on WSL。

💡 ONNX 模型导出

🐍 使用 Python (Ultralytics)

pip install ultralytics
python Snet.Py/Snet.Py.py

⌨️ 手动导出

# YOLOv5u–YOLOv12 (opset 17)
yolo export model=yolov8n.pt format=onnx opset=17

# YOLOv26 (opset 18)
yolo export model=yolo26n.pt format=onnx opset=18

📌 使用正确的 opset 版本可确保与 ONNX Runtime 的最佳兼容性与推理性能。

🐳 Docker 部署

🎯 发布工作流只打包仓库中真实存在的产品:WPF 发布 win-x64、win-x86;Tasks/API 的 CPU 版本发布 linux-x64、linux-arm64、win-x64,CUDA 版本发布 linux-x64、win-x64。GHCR 只构建 Tasks/API 的 Linux CPU 与 CUDA 镜像;仓库中的 Windows Dockerfile 用于手动构建,不在 GitHub Actions 镜像矩阵中。

🏗️ 构建镜像

# Linux CPU(Tasks 镜像包含 ffmpeg、ffprobe 与 Python)
docker build -t snet-yolo-tasks-cpu -f docker/Tasks.Cpu.Dockerfile .
docker build -t snet-yolo-api-cpu -f docker/Api.Cpu.Dockerfile .

# Linux CUDA(运行时需要 NVIDIA Container Toolkit)
docker build -t snet-yolo-tasks-cuda -f docker/Tasks.Cuda.Dockerfile .
docker build -t snet-yolo-api-cuda -f docker/Api.Cuda.Dockerfile .

🚀 运行容器

# CPU Tasks Web 工作台
docker run -d --name snet-yolo-tasks-cpu -p 8080:8080 \
  -v snet-tasks-data:/app/wwwroot/data \
  -v snet-tasks-db:/app/wwwroot/db \
  -v snet-tasks-train:/app/train \
  -v snet-tasks-sam:/app/sam \
  snet-yolo-tasks-cpu

# 确认镜像内 ffmpeg 和 ffprobe 都可用
docker exec snet-yolo-tasks-cpu ffmpeg -version
docker exec snet-yolo-tasks-cpu ffprobe -version

# CPU API
docker run -d -p 8080:8080 \
  -v /path/to/models:/app/wwwroot/onnxs \
  -v /path/to/data:/app/wwwroot \
  snet-yolo-api-cpu

curl http://localhost:8080/health   # 健康检查
curl http://localhost:8080/Operate/QueryAllAsync

📝 Linux Tasks 镜像中的 Debian ffmpeg 包同时提供 ffmpeg 和 ffprobe。CUDA 容器运行时需要 NVIDIA Container Toolkit 与可用 GPU。

Tasks 的 CPU/CUDA 镜像预先创建 /app/sam 并授权给非 root 运行用户;Windows Tasks 镜像对应 C:/app/sam,授予 ContainerUser 可继承的修改权限。SAM 卷保存下载的权重、active-model.json 与 .versions 中的更新/回退版本。重建或升级容器时,必须继续挂载同一个命名卷(例如 snet-tasks-sam);单独的 VOLUME 声明产生匿名卷,后续新容器不会自动复用它。不要删除 SAM 卷或以只读方式挂载;备份需包含整个 sam 目录。

CUDA Tasks 同样添加 -v snet-tasks-sam:/app/sam;Windows Tasks 使用 --mount type=volume,source=snet-tasks-sam,target=C:/app/sam。使用宿主机目录绑定挂载或已有卷时,挂载后的权限以宿主机/卷实际权限为准,镜像内授权不会自动修复:Linux 目录需允许镜像运行 UID 写入(可用 docker run --rm --entrypoint id <Tasks镜像> 查看,当前 CUDA 为 1654);Windows 目录需允许容器用户修改。不要让多个运行中的 Tasks 实例同时写入同一个 SAM 卷,版本切换只在单个服务进程内协调。

🧪 测试

# 🧪 单元测试(xUnit):上传中心、训练编排、数据集导出/体检、验证结果、媒体工具与 FFmpeg 安装等
dotnet test Snet.Yolo.Test/Snet.Yolo.Test.csproj

# Release 编译
dotnet build VisualIdentity.sln -c Release

🔒 安全特性

特性 实现方式 配置
🌐 CORS 控制 RestrictedOrigins 策略 appsettings.json → AllowedOrigins
🛡️ CSRF 防护 Tasks 的 Cookie 会话表单使用 Antiforgery Token;独立 API 保持无状态客户端兼容 登录、退出等浏览器表单
⏱️ 速率限制 固定窗口算法 RateLimit 配置节
🔐 安全响应头 中间件自动注入 X-Content-Type-Options / X-Frame-Options / CSP 等
📁 文件名净化 过滤路径遍历字符 + GUID 唯一化 上传处理逻辑
📏 文件大小限制 Kestrel + FormOptions 双重限制 API 默认图片 100 MiB、模型 1 GiB;Tasks 请求体与数据集 ZIP 同为 UploadCenter.MaxArchiveBytes(16 GiB)
🧹 数据自动清理 HistoryFileHandler 定时任务 RetentionDays(默认 30 天)

📈 性能优化

优化项 说明
🔄 模型实例缓存 配置不变时复用模型实例,避免重复加载
🧵 异步全链路 HTTP → GPU 推理 → 磁盘写入全链路 async/await
🖼️ 并行写盘 原图 / 标注图 / JSON 详情 Task.WhenAll 并行写入
💾 资源生命周期 WPF BitmapSource.Freeze() 支持跨线程显示,Skia/ONNX 对象按所有权及时释放

📌 实际延迟取决于模型、输入尺寸、执行提供程序、GPU、TensorRT 配置与存储性能;仓库不声明脱离具体硬件和模型的固定毫秒数。

📚 依赖组件

组件 说明
🔗 Snet.DB Dapper & SqlSugarCore 双 ORM,自动建表,Code-First 体验
⚡ YoloDotNet 超快速生产级 YOLO 推理库,支持 YOLOv5u → YOLOv26 全系列
🎨 SkiaSharp 跨平台 2D 渲染:图片解码、标注绘制、关键点渲染
🗄️ SQLite 嵌入式数据库:模型元数据管理

🙏 致谢

项目 说明
🌐 Snet.cn 项目官方网站
🔥 Ultralytics YOLO 模型训练与导出
🔍 Anomalib 工业异常检测模型训练、异常定位与 ONNX 导出
⚡ YoloDotNet .NET YOLO 推理引擎
🖥️ Snet.Windows.Controls WPF 现代化 UI 框架
🗄️ SqlSugarCore ORM 框架
🎨 SkiaSharp 跨平台图形渲染

📜 License

License: MIT

⚖️ 本项目基于 MIT 开源协议 —— 自由使用、修改、分发。

📄 完整条款请阅读 LICENSE 文件。

⚠️ 软件按「原样」提供,作者不对使用后果承担责任。

📈 Star History

Star History Chart

About

[ 开箱即用 ] 面向工业视觉检测的一站式平台,基于 ASP.NET Core 集成 YOLO、Anomalib 与 SAM,提供智能辅助标注、模型训练、异常定位、缺陷识别、联合验证和 API 服务。

Topics

Resources

Stars

41 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages