WPF-VisionMasterOpenCV

一、项目概述

WPF-VisionMasterOpenCV 是一个基于 WPF + EmguCV(OpenCV的.NET封装)开发的机器视觉软件框架。它采用节点流程图的方式,让用户可以通过拖拽节点来构建视觉检测流程。

项目架构

WPF-VisionMaster/
├── Document/           # 文档资源
├── Solution/           # 解决方案文件
└── Source/
    ├── Apps/           # 应用入口(主程序)
    │   └── H.App.VisionMaster.OpenCV/
    ├── NodeDatas/      # 节点数据定义(Onnx等)
    │   ├── H.NodeDatas.Onnx.OpenCV/
    │   └── H.NodeDatas.Zoo/
    ├── Setups/         # 安装包
    ├── VisionMaster/   # 核心视觉处理模块
    │   ├── H.VisionMaster.DiagramData/
    │   ├── H.VisionMaster.Network/
    │   ├── H.VisionMaster.NodeData/
    │   └── H.VisionMaster.OpenCV/  # ⭐ OpenCV节点核心
    └── WPF-Control/    # WPF控件库(依赖模块)

二、学习路径规划

阶段一:环境搭建与项目启动(第1-2天)

目标:能够成功编译并运行项目

1.1 准备开发环境
  • 必备工具
    • Visual Studio 2022(需安装 .NET 6/7 开发工具)
    • Git(用于拉取子模块)
1.2 克隆项目并恢复依赖
# 克隆主项目
git clone https://github.com/xxx/WPF-VisionMasterOpenCV.git

# 进入目录
cd WPF-VisionMasterOpenCV\WPF-VisionMasterOpenCV2.0\WPF-VisionMaster

# 初始化子模块(重要!)
git submodule init
git submodule update

# 打开解决方案
Start-Process Solution\WPF-VisionMaster.sln
1.3 理解启动流程

查看入口文件 Source/Apps/H.App.VisionMaster.OpenCV/App.xaml.cs

public partial class App : ApplicationBase
{
    protected override void ConfigureServices(IServiceCollection services)
    {
        services.AddApplicationServices();
        services.AddProject<VisionProjectService>(x =>
        {
            x.Extenstion = ".json";
            x.JsonSerializerService = new NewtonsoftJsonSerializerService();
        });
    }
}

关键点

  • 使用 Dependency Injection(依赖注入)模式
  • 项目配置使用 JSON 序列化
  • 继承自 ApplicationBase(来自 H.Extensions 库)

阶段二:核心概念理解(第3-5天)

目标:理解节点系统的设计模式

2.1 节点分类体系

项目中的节点按功能划分为多个类别:

类别 目录 功能说明
数据源 1 - Src/ 摄像头采集、图片读取、视频读取
预处理 2 - Preprocessings/ 颜色转换、阈值、缩放、翻转等
模糊处理 3 - Blurs/ 高斯模糊、均值模糊等
形态学 4 - Morphology/ 腐蚀、膨胀、开闭运算
条件判断 5 - Conditions/ 像素阈值判断等
模板匹配 6 - TemplateMatchings/ SIFT/SURF特征匹配、模板匹配
检测器 7 - Detector/ Canny边缘、Blob、轮廓检测
特征检测 8 - Feature/ AKaze、BRISK等特征点检测
其他 9 - Other/ YOLO、Haar级联、SVM等
输出 9 - Outputs/ OK/NG判定、消息通知
2.2 节点基类分析

查看典型节点实现,理解继承关系:

// 颜色转换节点
public class CvtColor : OpenCVNodeDataBase, IPreprocessingGroupableNodeData
{
    // 属性定义
    private ColorConversionCodes _colorConversionCode = ColorConversionCodes.BGR2GRAY;
    
    [Display(Name = "转换规则", GroupName = VisionPropertyGroupNames.RunParameters)]
    public ColorConversionCodes ColorConversionCode { get; set; }
    
    // 核心处理逻辑
    protected override FlowableResult<Mat> Invoke(
        ISrcVisionNodeData<Mat> srcImageNodeData, 
        IVisionNodeData<Mat> from, 
        IFlowableDiagramData diagram)
    {
        Mat mat = from.Mat.CvtColor(this.ColorConversionCode, this.DstCn);
        return this.OK(mat);
    }
}

关键接口说明

接口 作用
ISrcImageGroupableNodeData 数据源节点标记
IPreprocessingGroupableNodeData 预处理节点标记
IDetectorGroupableNodeData 检测器节点标记
IFlowableLinkData 节点间数据传递
IFlowableDiagramData 流程图上下文

阶段三:OpenCV扩展方法深入(第6-8天)

目标:掌握 OpenvCVExtension.cs 中的核心扩展方法

3.1 坐标转换方法
// WPF Rect ↔ OpenCV Rect 互转
public static System.Windows.Rect ToWindowRect(this Rect rect)
{
    return new System.Windows.Rect(rect.Left, rect.Top, rect.Width, rect.Height);
}

public static Rect ToCVRect(this System.Windows.Rect rect)
{
    return new Rect((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height);
}
3.2 颜色转换
// WPF Color ↔ OpenCV Scalar
public static Scalar ToScalar(this Color color)
{
    return Scalar.FromRgb(color.R, color.G, color.B);
}
3.3 HSV颜色范围计算(重要)
public static Tuple<Scalar, Scalar> GetHSVRange(this Color color, 
    int hRange = 30, int sRange = 20, int vRange = 20)
{
    // RGB转HSV,然后计算上下限范围
    // 用于颜色识别场景
}
3.4 图像转WPF控件
public static ImageSource ToImageSource(this Mat mat)
{
    if (!mat.IsValid()) return null;
    return Application.Current.Dispatcher.Invoke(() =>
    {
        return mat.ToWriteableBitmap();
    });
}

阶段四:典型节点实现学习(第9-12天)

目标:掌握不同类型节点的实现模式

4.1 数据源节点 - 摄像头采集
public class CameraCaptureNodeData : VideoCaptureNodeDataBase, ISrcImageGroupableNodeData
{
    public override async Task<IFlowableResult> InvokeAsync(...)
    {
        using VideoCapture capture = new VideoCapture();
        capture.Open(this.VideoCaptureIndex, this.VideoCaptureAPIs);
        
        // 循环采集帧
        while (true)
        {
            Mat frameMat = capture.RetrieveMat();
            // 处理帧...
            frameMat.Dispose();
        }
    }
}

关键点

  • 使用 VideoCapture 类读取摄像头
  • using 语句确保资源释放
  • await this.InvokeFrameMatAsync() 传递帧数据
4.2 预处理节点 - Canny边缘检测
public class Canny : OpenCVNodeDataBase, IDetectorGroupableNodeData
{
    [Range(50.0, 100.0)]
    public double Threshold1 { get; set; }
    
    [Range(150.0, 200.0)]
    public double Threshold2 { get; set; }
    
    protected override FlowableResult<Mat> Invoke(...)
    {
        Mat result = new Mat();
        Cv2.Canny(preMat, result, this.Threshold1, this.Threshold2, ...);
        return this.OK(result);
    }
}
4.3 高级节点 - YOLOv3目标检测
// 位于 9 - Other/Yolov3.cs
public class Yolov3 : OpenCVNodeDataBase, IDetectorGroupableNodeData
{
    // 配置模型路径
    private string _weights = "yolov3.cfg";
    private string _model = "yolov3.weights";
    
    protected override FlowableResult<Mat> Invoke(...)
    {
        // 使用 Dnn 模块加载 YOLO 模型
        using Net net = Cv2.Dnn.ReadNetFromDarknet(_weights, _model);
        // 推理检测...
    }
}

阶段五:创建自定义节点(第13-15天)

目标:能够编写自己的视觉处理节点

5.1 创建节点的步骤
using H.Controls.Diagram.Presenter.NodeDatas.Base;
using Emgu.CV;

// 1. 添加特性标记
[Icon(FontIcons.Custom)]
[Display(Name = "我的自定义节点", GroupName = "自定义", Description = "自定义处理逻辑")]

// 2. 继承基类并实现接口
public class MyCustomNode : OpenCVNodeDataBase, IPreprocessingGroupableNodeData
{
    // 3. 定义可配置属性
    private int _parameter = 10;
    [Display(Name = "参数", GroupName = "运行参数")]
    public int Parameter
    {
        get { return _parameter; }
        set { _parameter = value; RaisePropertyChanged(); }
    }
    
    // 4. 实现核心处理方法
    protected override FlowableResult<Mat> Invoke(
        ISrcVisionNodeData<Mat> srcImageNodeData,
        IVisionNodeData<Mat> from,
        IFlowableDiagramData diagram)
    {
        // 获取输入图像
        Mat inputMat = from.Mat;
        
        // 执行自定义处理
        Mat result = new Mat();
        // ... 你的 OpenCV 处理代码
        
        // 返回结果
        return this.OK(result);
    }
}
5.2 节点注册

创建节点后,需要在模块初始化时注册:

// 在扩展类中注册
public static class MyNodeExtension
{
    public static IServiceCollection AddMyCustomNode(this IServiceCollection services)
    {
        services.AddVisionNodeData<MyCustomNode>();
        return services;
    }
}

阶段六:实战项目开发(第16-20天)

目标:完成一个完整的视觉检测项目

6.1 项目案例:产品缺陷检测

流程设计

  1. 摄像头采集 → 获取实时图像
  2. 色彩变换 → 转灰度图
  3. 高斯模糊 → 降噪
  4. Canny边缘检测 → 提取边缘
  5. 轮廓查找 → FindContours
  6. Blob检测 → 识别缺陷区域
  7. OK/NG判定 → 根据缺陷数量输出结果
6.2 配置流程图
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  摄像头采集  │───▶│  色彩变换   │───▶│  高斯模糊   │
└─────────────┘    └─────────────┘    └─────────────┘
     │                                          │
     ▼                                          ▼
┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  Canny边缘  │───▶│  轮廓查找   │───▶│  Blob检测   │
└─────────────┘    └─────────────┘    └─────────────┘
                                              │
                                              ▼
                                    ┌─────────────┐
                                    │  OK/NG判定  │
                                    └─────────────┘

三、关键技术点总结

1. EmguCV 基础

类/方法 作用
Mat OpenCV图像容器
VideoCapture 视频/摄像头捕获
Cv2.Canny() 边缘检测
Cv2.GaussianBlur() 高斯模糊
Cv2.FindContours() 轮廓检测
Cv2.Dnn.ReadNetFromDarknet() 加载YOLO模型

2. WPF 集成要点

  • 线程安全:UI更新必须在 Dispatcher 线程执行
  • 图像转换Mat.ToImageSource() 方法
  • 数据绑定:使用 BindableBase 实现 MVVM

3. 节点生命周期

创建节点 → LoadDefault() → IsValid() → BeforeInvokeAsync() 
    → InvokeAsync() → UpdateResultImageSource() → 销毁

四、学习资源推荐

官方文档

参考项目

视频教程

  • B站搜索:WPF-VisionMaster 相关教程
  • OpenCV 入门视频

五、练习建议

  1. 入门练习:修改现有节点参数,观察效果变化
  2. 基础练习:创建一个简单的自定义节点(如亮度调整)
  3. 进阶练习:实现一个完整的检测流程(如二维码识别)
  4. 高级练习:集成自定义深度学习模型

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐