【工控实战】基于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 首次运行

  1. 程序启动后显示登录窗体
  2. 使用以下内置账号登录:
用户名 密码 权限
Operator operator123 运行检测、查看结果
Engineer engineer123 编辑模板、调整参数(修改需二次确认密码)
Admin admin123 导出数据、用户管理(增删改用户)
  1. 登录后默认进入实时检测页面
  2. 在顶部"模板"下拉框选择任意模板
  3. 点击开始检测运行单次检测;勾选连续模式后可持续轮询
  4. 右侧面板实时显示 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 的坐标映射是很多初学者卡壳的地方。核心记住两点:

  1. 鼠标事件拿到的是控件坐标(e.X, e.Y)
  2. 算法层使用的是图像坐标(像素位置)
  3. 绘制时使用的是显示坐标(经过缩放和平移后的屏幕位置)

三者通过 ControlToImage()ImageToControl() 双向转换,所有 ROI 操作(绘制、移动、命中测试)都基于这套映射。

9.4 关于 AI 协同开发

本项目开发过程中,采用 AI 辅助编程(Kimi / Cursor)进行:

  • 整体架构设计与模块划分
  • 状态机流程和事件总线模式
  • ImageCanvas 的坐标映射和交互逻辑框架
  • 数据库表结构和 Repository 模式模板
  • 代码审查与重构建议

AI 能做好的:重复性代码生成、模式模板、边界条件提醒
AI 做不好的:ROI 交互的精细体验调优、工业现场的异常场景覆盖、性能敏感算法的参数整定

核心业务逻辑(状态机设计、ROI 命中测试、检测流程编排)仍需人工把控。


十、总结与展望

本项目通过配置化的设计思路,将视觉检测中"硬编码"的痛点转化为"模板化"的便利。核心亮点:

  1. 状态机驱动的检测流程——InspectionEngine 的严谨状态管理,杜绝非法操作
  2. 自定义 ImageCanvas 控件——完整的三坐标系映射 + ROI 交互,工业级体验
  3. 算法插件化架构——IInspectionAlgorithm 接口统一,扩展零侵入
  4. WinForms + WPF 双版本——WinForms 负责稳定交付,WPF 负责技术展示
  5. 完整的数据追溯——SQLite + CSV 导出 + 操作日志,满足工厂审计要求
  6. 三级权限管控——操作员/工程师/管理员,参数修改二次确认

后续优化方向

  • 接入真实相机 SDK(海康 MVision、Basler Pylon)
  • 集成 Halcon 商业视觉库,提升复杂缺陷检测精度
  • 引入 AI 缺陷分类模型(YOLO / ONNX Runtime)
  • 支持 MQTT 上报检测结果到 MES 系统
  • 多语言国际化(中文/英文/日文)

十一、源码获取与使用声明

版权声明:本文为技术分享,项目代码已脱敏处理,不含任何真实客户信息、设备型号或工艺参数。仅供学习交流使用。

如需获取完整源码,可通过以下方式联系作者(请在 CSDN 私信或评论区留言)。


如果这篇文章对你有帮助,欢迎点赞、收藏、转发,有问题欢迎在评论区留言交流!

Logo

一站式 AI 云服务平台

更多推荐