【工控实战】基于C# .NET 10 + OpenCVSharp 的通用视觉检测平台完整实现(附源码结构)
【工控实战】基于C# .NET 10 + OpenCVSharp 的通用视觉检测平台完整实现(附源码结构)
本文导读:一套面向半导体、光伏、锂电行业的通用视觉检测上位机软件完整实现。采用 .NET 10 + WinForms/WPF 双版本、OpenCVSharp4 图像处理、SQLite 数据追溯、INI 配置化换型。无需真实相机,内置模拟图像,下载即可运行。文末提供核心模块完整代码解析。
关键词:C#上位机、WinForms、WPF、OpenCVSharp、视觉检测、工业自动化、ROI交互、状态机、SQLite、配置化换型
文章目录
一、前言:为什么要写这篇文章
在工业自动化领域,视觉检测是质量管控的核心环节。传统开发模式下,每换一款产品就要重写检测逻辑、重新编译部署,调试周期长、维护成本高。
本文分享的项目核心思路是**“配置化换型”——通过 ROI 交互绘制 + 算法链编排 + INI 模板保存,实现零代码适配新产品**。操作员在 UI 上画个框、调个阈值、保存模板,即可上线检测。
项目已脱敏处理,所有设备名称、工艺参数均为虚构值,可直接用于学习交流。
你能从本文学到什么:
- 工业视觉检测上位机的完整架构设计
- 基于状态机的严谨检测流程控制
- 自定义 ROI 交互画布(矩形/圆形绘制、移动、缩放)
- 算法插件化设计(热插拔扩展)
- SQLite 本地数据追溯 + CSV 导出
- 权限分级(操作员/工程师/管理员)
二、项目概述
2.1 适用场景
| 行业 | 检测对象 | 缺陷类型 |
|---|---|---|
| 半导体 | 晶圆外观 | 划痕、缺角、污染、未找到圆 |
| 光伏 | 电池片 | 栅线断裂、黑斑、边缘缺陷 |
| 锂电 | 极片/电芯 | 划痕、凹坑、异物、尺寸超差 |
2.2 核心特性
| 特性 | 说明 |
|---|---|
| 配置化换型 | INI 模板保存检测参数,无需修改代码即可切换产品 |
| ROI 交互绘制 | 自定义 Canvas 控件,支持矩形/圆形 ROI 的绘制、移动、删除 |
| 插件化算法 | 统一 IInspectionAlgorithm 接口,新算法只需实现接口即可接入 |
| 状态机驱动 | 检测流程严格按状态机流转,非法操作直接拦截 |
| 双版本 UI | WinForms 版本(稳定成熟)+ WPF 版本(Material Design 现代化) |
| 数据追溯 | SQLite 本地存储,支持检测记录查询、CSV 导出、近7天良率统计 |
| 权限管控 | 三级账号:Operator(操作)/ Engineer(调参)/ Admin(管理) |
| 零硬件依赖 | 内置模拟图像文件夹轮询,无需连接真实相机即可演示 |
三、技术栈选型(真实版本)
├── 开发语言:C# 13
├── 运行时:.NET 10
├── UI框架:WinForms(主版本)+ WPF(次版本)
├── 图像处理:OpenCvSharp4
├── 数据存储:Microsoft.Data.Sqlite(SQLite)
├── 配置格式:INI 纯文本(零第三方依赖)
├── 图表组件:ScottPlot(WPF 版本统计图表)
├── 架构模式:分层架构 + 服务层隔离 + 事件总线
└── 日志系统:自定义文本文件日志(零第三方依赖)
选型理由:
- .NET 10:用最新 LTS 路线,享受新语言特性和性能优化;但代价是 WinForms 设计器兼容性(后面会讲坑)。
- WinForms:工控领域绝对主流,开发效率高,部署简单(单 exe 即可运行),现场工程师熟悉。
- WPF 版本:使用 MaterialDesign 主题 + MVVM 模式,作为技术展示和技术储备。
- OpenCVSharp:OpenCV 的 C# 封装,功能完整,Halcon 的免费平替,适合学习和中小项目。
- SQLite:零配置、单文件,工控机本地存储的最佳选择。
- INI 格式:遵循"离线零依赖"原则,不引入 Newtonsoft.Json 等第三方库,现场可直接手动修改配置。
- ScottPlot:WPF 版本用于绘制近7天 OK/NG 柱状图和良率趋势折线图,轻量无广告。
四、系统架构设计
4.1 总体架构(树状图)
通用视觉检测平台
│
├─ UI 表现层
│ ├─ WinForms 版本 (VisionApp)
│ │ ├─ Forms/ → MainForm、LoginForm、TemplateEditForm、LogQueryForm
│ │ ├─ Pages/ → InspectionPage、TemplatePage、DataPage、LogPage、SystemPage
│ │ └─ Controls/ → ImageCanvas(核心自定义图像控件)、LogListView、NavigationBar
│ │
│ └─ WPF 版本 (VisionApp.Wpf)
│ ├─ Views/ → 对应各功能页面的 XAML 视图
│ ├─ ViewModels/ → MVVM 模式数据绑定
│ ├─ Controls/ → ImageCanvas.xaml、NavigationRail.xaml
│ └─ Converters/ → 值转换器(BoolToVisibility、ResultColor 等)
│
├─ 服务层 (Vision.Core/Services)
│ ├─ IInspectionService / InspectionService → 检测流程 orchestration
│ ├─ ITemplateService / TemplateService → 模板的 CRUD 与切换
│ ├─ IStatisticsService / StatisticsService → 统计聚合(近7天良率)
│ ├─ IExportService / ExportService → CSV 导出
│ ├─ IOperationLogService / OperationLogService→ 操作日志记录
│ └─ IUserService / UserService → 登录认证与权限校验
│
├─ 业务逻辑层 (Vision.Core)
│ ├─ InspectionFlow/
│ │ ├─ InspectionEngine.cs → 检测引擎(核心状态机)
│ │ ├─ InspectionContext.cs → 单次检测的上下文(图像、结果、模板)
│ │ └─ InspectionState.cs → 状态枚举定义
│ ├─ TemplateManager/
│ │ ├─ ProductTemplate.cs → 模板数据模型
│ │ ├─ AlgorithmChain.cs → 算法链(多算法顺序执行,支持 NG 即停/继续)
│ │ ├─ JudgmentRule.cs → 判定规则(阈值、容差)
│ │ └─ TemplateRepository.cs → 模板的持久化(INI 读写)
│ ├─ ResultManager/
│ │ ├─ InspectionResult.cs → 单次检测结果
│ │ ├─ DefectInfo.cs → 缺陷详情
│ │ └─ StatisticsAggregator.cs→ 统计数据聚合
│ ├─ UserManager/
│ │ ├─ UserAccount.cs → 用户账号模型
│ │ ├─ UserRole.cs → 角色枚举
│ │ └─ UserService.cs → 用户认证服务(单例)
│ └─ Visualization/
│ └─ ResultVisualizer.cs → 结果可视化逻辑(坐标转换、颜色映射)
│
├─ 算法层 (Vision.Algorithm)
│ ├─ Interfaces/
│ │ └─ IInspectionAlgorithm.cs → 统一算法接口
│ ├─ Detectors/
│ │ ├─ GeometryDetector.cs → 几何测量(圆、线)
│ │ ├─ TemplateMatcher.cs → 模板匹配定位
│ │ └─ GrayDefectDetector.cs → 灰度缺陷检测(阈值+轮廓)
│ ├─ Preprocessing/
│ │ └─ ImagePreprocessor.cs → 图像预处理管道
│ └─ Models/
│ ├─ ROI.cs → ROI 数据模型(矩形/圆形)
│ ├─ AlgorithmParam.cs → 算法参数基类
│ └─ AlgorithmResult.cs → 算法结果
│
├─ 数据访问层 (Vision.Data)
│ ├─ Database/
│ │ ├─ SqliteDbContext.cs → SQLite 连接上下文
│ │ └─ DatabaseInitializer.cs → 数据库初始化(首次运行自动建表)
│ ├─ Repositories/
│ │ ├─ InspectionRecordRepository.cs → 检测记录 CRUD
│ │ └─ OperationLogRepository.cs → 操作日志 CRUD
│ ├─ Entities/
│ │ ├─ InspectionRecord.cs → 检测记录实体
│ │ ├─ DefectItem.cs → 缺陷明细实体
│ │ └─ OperationLog.cs → 操作日志实体
│ ├─ Exporters/
│ │ └─ CsvExporter.cs → CSV 导出实现
│ └─ Common/
│ ├─ Logger.cs → 单例日志器(线程安全)
│ ├─ EventBus.cs → 轻量级事件总线(跨模块通信)
│ ├─ AppConfig.cs → 应用配置(单例)
│ └─ IniFileHelper.cs → INI 文件读写工具
│
└─ 工具层 (tools/)
├─ GenerateTestImages/ → C# 测试图像生成器(光伏电池片 + 晶圆)
└─ DemoDataSeeder/ → 演示数据种子(预置检测记录)
架构设计要点:
- 服务层隔离:UI 不直接调用业务逻辑,而是通过 Service 接口交互,便于后续单元测试和 UI 替换。
- 事件总线:InspectionEngine 的状态变更通过 EventBus 广播,UI 层订阅后更新状态显示,解耦检测流程与界面刷新。
- 单例线程安全:Logger、AppConfig、UserService 均采用
lock或静态初始化保证线程安全。
五、核心模块实现
5.1 检测引擎状态机(InspectionEngine)
检测流程采用状态机模式管理,这是整个项目最核心的设计。状态机确保流程严谨可控,任何非法状态转换都会被拦截。
// 本文件实现检测流程引擎。
// 采用状态机模式管理检测全流程,包括加载图像、预处理、算法检测、结果判定和数据保存。
public enum InspectionState
{
Idle, // 空闲
Ready, // 就绪(模板已加载)
LoadingImage, // 图像采集中
Preprocessing, // 预处理
Detecting, // 算法检测中
Judging, // 结果判定
Saving, // 数据保存
Error // 异常
}
状态流转规则:
Idle → Ready(加载模板后)
Ready → LoadingImage → Preprocessing → Detecting → Judging → Saving → Ready(单次检测完整流程)
任意状态 ──异常──→ Error → Idle(复位)
/// <summary>
/// 检测引擎类,负责驱动整个检测流程状态机。
/// </summary>
public class InspectionEngine
{
// 当前检测状态。
private InspectionState _currentState;
// 状态切换时的线程锁,确保状态变更线程安全。
private readonly object _stateLock;
// 检测取消令牌源,用于停止连续检测。
private CancellationTokenSource _cancellationTokenSource;
// 当前检测上下文。
private InspectionContext _context;
// 当前加载的产品模板。
private ProductTemplate _currentTemplate;
// 模拟图像源,按文件名顺序加载图片。
private List<string> _simulationImagePaths;
// 当前模拟图像索引。
private int _simulationImageIndex;
/// <summary>
/// 当检测状态改变时触发。
/// </summary>
public event Action<InspectionState> StateChanged;
/// <summary>
/// 当单次检测完成时触发。
/// </summary>
public event Action<InspectionResult> InspectionCompleted;
/// <summary>
/// 当发生错误时触发。
/// </summary>
public event Action<string> ErrorOccurred;
/// <summary>
/// 默认构造函数。
/// </summary>
public InspectionEngine()
{
_stateLock = new object();
_cancellationTokenSource = new CancellationTokenSource();
_context = new InspectionContext();
_simulationImagePaths = new List<string>();
_simulationImageIndex = 0;
ChangeState(InspectionState.Idle);
}
/// <summary>
/// 启动单次检测流程。
/// </summary>
public void StartInspection()
{
Task.Run(() => RunInspectionOnce());
}
/// <summary>
/// 启动连续检测模式。
/// </summary>
public void StartContinuousInspection()
{
_cancellationTokenSource = new CancellationTokenSource();
CancellationToken token = _cancellationTokenSource.Token;
Task.Run(() =>
{
while (!token.IsCancellationRequested)
{
RunInspectionOnce();
Thread.Sleep(AppConfig.Instance.SimulationIntervalMs);
}
}, token);
}
/// <summary>
/// 停止连续检测。
/// </summary>
public void StopInspection()
{
try
{
_cancellationTokenSource?.Cancel();
ChangeState(InspectionState.Ready);
Logger.Instance.Info("检测已停止");
}
catch (Exception ex)
{
Logger.Instance.Error(ex, "停止检测异常");
}
}
/// <summary>
/// 执行一次完整的检测流程。
/// </summary>
private void RunInspectionOnce()
{
if (_currentTemplate == null)
{
ErrorOccurred?.Invoke("未加载模板,无法检测");
return;
}
InspectionResult result = new InspectionResult();
try
{
ChangeState(InspectionState.LoadingImage);
Mat sourceImage = LoadNextSimulationImage();
if (sourceImage == null || sourceImage.Empty())
{
throw new Exception("无法加载模拟图像");
}
_context.SourceImage = sourceImage;
_context.ProcessedImage = sourceImage.Clone();
ChangeState(InspectionState.Preprocessing);
PreprocessImage();
ChangeState(InspectionState.Detecting);
List<AlgorithmResult> algorithmResults = RunAlgorithms();
ChangeState(InspectionState.Judging);
result = JudgeResult(algorithmResults);
ChangeState(InspectionState.Saving);
SaveResult(result);
ChangeState(InspectionState.Ready);
InspectionCompleted?.Invoke(result);
}
catch (Exception ex)
{
Logger.Instance.Error(ex, "检测流程异常");
ChangeState(InspectionState.Error);
ErrorOccurred?.Invoke("检测异常:" + ex.Message);
}
}
/// <summary>
/// 切换检测状态,并触发状态改变事件。
/// </summary>
/// <param name="newState">新的检测状态。</param>
private void ChangeState(InspectionState newState)
{
lock (_stateLock)
{
_currentState = newState;
}
try
{
StateChanged?.Invoke(newState);
EventBus.Instance.PublishInspectionStateChanged(newState.ToString());
}
catch (Exception ex)
{
Logger.Instance.Error(ex, "触发状态改变事件失败");
}
}
}
设计要点:
- 线程安全:状态变更使用
lock加锁,防止多线程竞态。 - CancellationToken:连续检测模式下,点击"停止"立即通过
Cancel()中断循环,不会卡在图像加载或算法执行中。 - 异常兜底:任何步骤抛异常都会进入
Error状态,日志记录完整堆栈,UI 显示友好错误信息。 - EventBus 广播:状态变更同时通过事件委托和事件总线双通道通知,确保 UI 和日志模块都能响应。
5.2 自定义图像控件(ImageCanvas)
ImageCanvas 是整个项目最复杂的自定义控件,继承自 UserControl,负责图像显示、ROI 交互、结果叠加三大功能。
// 本文件实现自定义图像显示控件。
// 支持显示 OpenCV Mat 图像、ROI 叠加绘制、ROI 交互绘制/选中/移动/删除、缩放和平移。
public partial class ImageCanvas : UserControl
{
// 当前显示的 OpenCV 图像。
private Mat _currentImage;
// 当前显示的位图缓存,用于双缓冲绘制。
private Bitmap _displayBitmap;
// 图像缩放比例。
private double _zoomScale;
// 图像在控件中的水平/垂直偏移量。
private double _offsetX;
private double _offsetY;
// 是否正在拖动图像。
private bool _isPanning;
// 当前要绘制的 ROI 列表。
private List<ROI> _rois;
// 当前选中的 ROI。
private ROI _selectedRoi;
// 当前画布工作模式。
private CanvasMode _mode;
/// <summary>
/// 将图像坐标转换为控件坐标。
/// </summary>
public PointF ImageToControl(PointF imagePoint)
{
float x = (float)(imagePoint.X * _zoomScale + _offsetX);
float y = (float)(imagePoint.Y * _zoomScale + _offsetY);
return new PointF(x, y);
}
/// <summary>
/// 将控件坐标转换为图像坐标。
/// </summary>
public PointF ControlToImage(PointF controlPoint)
{
float x = (float)((controlPoint.X - _offsetX) / _zoomScale);
float y = (float)((controlPoint.Y - _offsetY) / _zoomScale);
return new PointF(x, y);
}
}
交互逻辑:
| 操作 | 功能 |
|---|---|
| 左键拖拽空白处 | 平移图像 |
| 左键拖拽 ROI | 移动 ROI 位置 |
| 右键 | 弹出上下文菜单(删除 ROI、自适应图像) |
| 滚轮 | 以鼠标位置为中心缩放图像(范围 0.1x ~ 10x) |
| Delete 键 | 删除当前选中的 ROI |
绘制流程(OnPaint):
1. 清空背景
2. 绘制图像(按缩放比例和偏移量)
3. 绘制所有 ROI(选中为黄色,未选中为 ROI 自定义颜色)
4. 绘制 ROI 名称标签
5. 绘制检测结果叠加(OK 绿框 / NG 红框、缺陷包围框、文字提示)
6. 绘制整体结果大文字(OK 绿色 / NG 红色)
坐标映射系统:
ImageCanvas 的核心难点在于三套坐标系的实时转换:
- 图像坐标系:原始图像像素坐标(算法层使用)
- 控件坐标系:WinForms 控件的客户区坐标(鼠标事件使用)
- 显示坐标系:经过缩放和平移后的实际绘制位置
ImageToControl() 和 ControlToImage() 两个方法实现了图像坐标与控件坐标的双向映射,所有 ROI 绘制、命中测试、移动操作都基于这套映射。
5.3 算法插件化设计
所有检测算法实现统一接口,新算法只需实现 IInspectionAlgorithm 即可接入系统,无需修改 UI 或引擎代码。
// 本文件定义所有检测算法的统一接口。
// 通过该接口可以实现算法插件化,便于后续扩展新的检测算法。
public interface IInspectionAlgorithm
{
/// <summary>
/// 获取算法显示名称。
/// </summary>
string AlgorithmName { get; }
/// <summary>
/// 获取算法类型标识,例如 Geometry、TemplateMatch、GrayDefect。
/// </summary>
string AlgorithmType { get; }
/// <summary>
/// 获取或设置算法参数。
/// </summary>
AlgorithmParam Parameters { get; set; }
/// <summary>
/// 对指定图像的 ROI 区域执行检测。
/// </summary>
/// <param name="sourceImage">原始图像。</param>
/// <param name="roi">感兴趣区域。</param>
/// <returns>算法执行结果。</returns>
AlgorithmResult Execute(Mat sourceImage, ROI roi);
/// <summary>
/// 校验当前参数是否合法。
/// </summary>
/// <returns>参数合法返回 true。</returns>
bool ValidateParameters();
}
内置三种算法:
| 算法 | 核心 API | 适用场景 | 输出 |
|---|---|---|---|
| GeometryDetector | Cv2.HoughCircles() / Cv2.FitLine() |
圆直径、线间距、角度测量 | 测量值 + 是否超差 |
| TemplateMatcher | Cv2.MatchTemplate() + Cv2.MinMaxLoc() |
特征定位、有无判断 | 匹配分数 + 位置 |
| GrayDefectDetector | Cv2.Threshold() + Cv2.FindContours() |
污点、划痕、色差 | 缺陷列表 + 面积 |
算法链(AlgorithmChain):
一个模板可配置多个算法节点,按顺序执行。支持两种模式:
- NG 即停(默认):任一算法发现缺陷,立即停止后续检测,快速判定 NG。
- 全量检测:所有算法都执行完,汇总全部缺陷信息(用于需要统计所有缺陷类型的场景)。
5.4 配方模板系统(INI 格式)
模板是项目的核心数据模型,每个产品对应一个模板文件,存放在 data/templates/ 目录下。
data/templates/
├── 半导体晶圆模板.ini
├── 太阳能电池片模板.ini
└── 通用缺陷检测模板.ini
模板切换流程:
用户选择模板
↓
TemplateRepository 读取 INI 文件
↓
解析为 ProductTemplate 对象(ROIs + AlgorithmChain + JudgmentRule)
↓
InspectionEngine.LoadTemplate(template)
↓
状态变为 Ready,可开始检测
INI 格式优势(对比 JSON):
- 零依赖:无需 Newtonsoft.Json 等第三方库,减少部署体积和许可证风险。
- 现场可修:工程师可直接用记事本打开 INI 文件修改阈值,无需安装任何工具。
- 注释友好:INI 支持分号注释,方便现场标注参数含义。
- 防呆设计:自定义
IniFileHelper封装了所有读写操作,带 try-catch 和默认值回退。
参数修改二次确认:
工程师账号在模板编辑界面调整算法参数后,点击"确定"保存时,系统会弹窗要求重新输入当前用户密码进行二次确认。这是工业现场的常见需求——防止误操作导致整批产品参数被改。
六、界面展示
以下截图展示了系统的主要界面,采用深色工业主题风格(深灰背景 + 蓝色强调色),左侧导航栏、右侧内容区、圆角卡片布局。
6.1 实时检测界面

界面布局:
- 左侧导航栏:实时检测、模板管理、检测记录、数据统计、操作日志、系统设置(带图标 + 选中高亮)
- 顶部工具栏:模板选择下拉框、开始检测按钮、停止按钮、连续模式复选框、状态显示(Ready / Detecting 等)
- 中间图像区:ImageCanvas 控件,显示当前检测图像,叠加 ROI 框和缺陷标记
- 右侧结果面板:
- 检测结果大字(OK 绿色 / NG 红色)
- 检测时间戳
- 缺陷列表(类型、分数、ROI)
- 统计概览(总产量、OK 数、NG 数、良率)
操作方式:选择模板 → 点击"开始检测"运行单次检测;勾选"连续模式"后可持续轮询模拟图像。
6.2 模板管理界面

- 支持新建、编辑、克隆、删除、设为当前模板
- 预设三个模板:半导体晶圆模板、太阳能电池片模板、通用缺陷检测模板
- 以 Engineer 或 Admin 账号登录后可编辑模板
6.3 检测记录与 CSV 导出

- 检测记录表格:记录编号(REC-YYYYMMDD-XXX)、模板名称、时间、结果、缺陷数、操作员
- 统计概览栏:总产量、OK 数、NG 数、良率(实时汇总)
- 导出 CSV:一键导出当前查询结果到 CSV 文件
6.4 数据统计(近7天趋势)

- 近7天 OK/NG 数量柱状图:每日产量分布,绿色 OK / 红色 NG
- 近7天良率趋势折线图:蓝色折线展示每日良率变化,快速发现质量波动
6.5 操作日志追溯

- 时间范围查询:开始时间 / 结束时间选择器
- 用户筛选:按操作员账号过滤
- 操作类型筛选:Login / StartInspection / StopInspection / SaveTemplate / DeleteTemplate / ExportData
- 导出 CSV:审计追踪必备
七、数据库设计
首次运行程序时,DatabaseInitializer 自动创建 SQLite 数据库文件 data/database/vision.db。
-- 检测记录主表
CREATE TABLE InspectionRecords (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
RecordId TEXT NOT NULL UNIQUE, -- 业务编号:REC-20260715-001
TemplateName TEXT NOT NULL, -- 使用的模板名称
InspectionTime DATETIME NOT NULL, -- 检测时间
OverallResult TEXT NOT NULL, -- OK / NG
ImagePath TEXT, -- 原始图像路径
Operator TEXT, -- 操作员账号
TotalDefectCount INTEGER DEFAULT 0, -- 缺陷总数
Remark TEXT -- 备注
);
-- 缺陷明细表(一对多关联)
CREATE TABLE DefectItems (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
RecordId TEXT NOT NULL, -- 关联 InspectionRecords.RecordId
DefectType TEXT NOT NULL, -- 缺陷类型
ROIName TEXT, -- 所在 ROI 名称
Score REAL, -- 检测分数
PositionX REAL, -- 缺陷位置 X
PositionY REAL -- 缺陷位置 Y
);
-- 操作日志表(审计追踪)
CREATE TABLE OperationLogs (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
LogTime DATETIME NOT NULL, -- 操作时间
UserName TEXT NOT NULL, -- 操作账号
ActionType TEXT NOT NULL, -- 操作类型
ActionDetail TEXT, -- 操作详情
Result TEXT -- 执行结果 Success / Failed
);
-- 用户账号表
CREATE TABLE UserAccounts (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
UserName TEXT NOT NULL UNIQUE, -- 登录账号
PasswordHash TEXT NOT NULL, -- 密码哈希
DisplayName TEXT, -- 显示名称
Role TEXT NOT NULL, -- Operator / Engineer / Admin
IsActive INTEGER DEFAULT 1, -- 是否启用
CreatedTime DATETIME -- 创建时间
);
八、运行说明
8.1 环境要求
| 组件 | 版本要求 | 备注 |
|---|---|---|
| 操作系统 | Windows 10/11 | x64 |
| .NET SDK | .NET 10 | 必须安装 .NET 10 SDK |
| 开发工具 | VS 2022 Preview 17.14+ | ⚠️ 稳定版 VS 2022 不支持 .NET 10 的 WinForms 设计器 |
| 备选 IDE | JetBrains Rider | 需确认支持 .NET 10 WinForms 设计器 |
重要提示:这是 .NET 10 项目的最大坑点!如果你用稳定版 VS 2022 打开项目,WinForms 设计器会报错或无法显示控件。解决方案:安装 VS 2022 Preview,或将项目改回
net8.0-windows(需修改所有 .csproj 文件)。
8.2 快速启动
# 1. 进入项目目录
cd e:\Game\DEMO_1
# 2. 编译
dotnet build VisionInspectionPlatform.slnx
# 3. 运行 WinForms 版本
dotnet run --project src/VisionApp/VisionApp.csproj
# 4. 或运行 WPF 版本
dotnet run --project src/VisionApp.Wpf/VisionApp.Wpf.csproj
8.3 首次运行
- 程序启动后显示登录窗体
- 使用以下内置账号登录:
| 用户名 | 密码 | 权限 |
|---|---|---|
| Operator | operator123 | 运行检测、查看结果 |
| Engineer | engineer123 | 编辑模板、调整参数(修改需二次确认密码) |
| Admin | admin123 | 导出数据、用户管理(增删改用户) |
- 登录后默认进入实时检测页面
- 在顶部"模板"下拉框选择任意模板
- 点击开始检测运行单次检测;勾选连续模式后可持续轮询
- 右侧面板实时显示 OK/NG 结果和统计信息
8.4 生成测试图像
如果 data/images/simulation/ 目录下没有图片,运行测试图生成工具:
dotnet run --project tools/GenerateTestImages/GenerateTestImages.csproj
会自动生成 10 张光伏电池片图和 10 张晶圆图,用于模拟检测。
九、踩坑经验与工程实践
9.1 .NET 10 + WinForms 设计器兼容性(必看)
这是本项目最大的环境坑:
- .NET 10 的 WinForms 设计器需要 VS 2022 Preview 17.14+
- 稳定版 VS 2022(哪怕是 17.13)打开
MainForm.Designer.cs会报设计器错误 - 如果你不想装 Preview 版,解决方案:把所有
.csproj中的net10.0-windows改成net8.0-windows,然后重新还原 NuGet 包
9.2 自定义控件的设计器兼容
ImageCanvas 继承自 UserControl,在构造函数中加了设计器模式判断:
if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
{
return; // 设计器模式下不创建运行时对象
}
如果不加这个判断,VS 设计器加载控件时会尝试调用 OpenCV 相关代码,导致设计器崩溃。
9.3 图像坐标 vs 控件坐标
ImageCanvas 的坐标映射是很多初学者卡壳的地方。核心记住两点:
- 鼠标事件拿到的是控件坐标(e.X, e.Y)
- 算法层使用的是图像坐标(像素位置)
- 绘制时使用的是显示坐标(经过缩放和平移后的屏幕位置)
三者通过 ControlToImage() 和 ImageToControl() 双向转换,所有 ROI 操作(绘制、移动、命中测试)都基于这套映射。
9.4 关于 AI 协同开发
本项目开发过程中,采用 AI 辅助编程(Kimi / Cursor)进行:
- 整体架构设计与模块划分
- 状态机流程和事件总线模式
- ImageCanvas 的坐标映射和交互逻辑框架
- 数据库表结构和 Repository 模式模板
- 代码审查与重构建议
AI 能做好的:重复性代码生成、模式模板、边界条件提醒
AI 做不好的:ROI 交互的精细体验调优、工业现场的异常场景覆盖、性能敏感算法的参数整定
核心业务逻辑(状态机设计、ROI 命中测试、检测流程编排)仍需人工把控。
十、总结与展望
本项目通过配置化的设计思路,将视觉检测中"硬编码"的痛点转化为"模板化"的便利。核心亮点:
- 状态机驱动的检测流程——
InspectionEngine的严谨状态管理,杜绝非法操作 - 自定义 ImageCanvas 控件——完整的三坐标系映射 + ROI 交互,工业级体验
- 算法插件化架构——
IInspectionAlgorithm接口统一,扩展零侵入 - WinForms + WPF 双版本——WinForms 负责稳定交付,WPF 负责技术展示
- 完整的数据追溯——SQLite + CSV 导出 + 操作日志,满足工厂审计要求
- 三级权限管控——操作员/工程师/管理员,参数修改二次确认
后续优化方向:
- 接入真实相机 SDK(海康 MVision、Basler Pylon)
- 集成 Halcon 商业视觉库,提升复杂缺陷检测精度
- 引入 AI 缺陷分类模型(YOLO / ONNX Runtime)
- 支持 MQTT 上报检测结果到 MES 系统
- 多语言国际化(中文/英文/日文)
十一、源码获取与使用声明
版权声明:本文为技术分享,项目代码已脱敏处理,不含任何真实客户信息、设备型号或工艺参数。仅供学习交流使用。
如需获取完整源码,可通过以下方式联系作者(请在 CSDN 私信或评论区留言)。
如果这篇文章对你有帮助,欢迎点赞、收藏、转发,有问题欢迎在评论区留言交流!
更多推荐




所有评论(0)