文章目录
- [1. 功能介绍](#1. 功能介绍)
-
- [1.1 核心特性](#1.1 核心特性)
- [2. 核心API详解](#2. 核心API详解)
-
- [2.1 文件读写方法](#2.1 文件读写方法)
-
- [2.1.1 `SaveObjectToFile`---保存对象到文件](#2.1.1
SaveObjectToFile—保存对象到文件) - [2.1.2 `LoadObjectFromFile`---从文件加载对象](#2.1.2
LoadObjectFromFile—从文件加载对象)
- [2.1.1 `SaveObjectToFile`---保存对象到文件](#2.1.1
- [2.2 内存流读写方法](#2.2 内存流读写方法)
-
- [2.2.1 `SaveObjectToStream`---保存对象到内存流](#2.2.1
SaveObjectToStream—保存对象到内存流) - [2.2.2 `LoadObjectFromStream`---从内存流加载对象](#2.2.2
LoadObjectFromStream—从内存流加载对象)
- [2.2.1 `SaveObjectToStream`---保存对象到内存流](#2.2.1
- [2.3 深度复制方法](#2.3 深度复制方法)
-
- [2.3.1 `DeepCopyObject`---深度复制(官方推荐)](#2.3.1
DeepCopyObject—深度复制(官方推荐)) - [2.3.2 `CogSerializationOptionsConstants`枚举详解](#2.3.2
CogSerializationOptionsConstants枚举详解) -
- [2.3.2.1 选项组合使用](#2.3.2.1 选项组合使用)
- [2.3.2.2 选项选择建议](#2.3.2.2 选项选择建议)
- [2.3.1 `DeepCopyObject`---深度复制(官方推荐)](#2.3.1
- [3. 代码示例](#3. 代码示例)
-
- [3.1 示例 1:基本的保存与加载](#3.1 示例 1:基本的保存与加载)
- [3.2 示例 2:多粒度保存策略](#3.2 示例 2:多粒度保存策略)
- [3.3 示例 3:使用流进行内存复制与多版本管理](#3.3 示例 3:使用流进行内存复制与多版本管理)
- [3.4 示例 4:批量配置文件管理器](#3.4 示例 4:批量配置文件管理器)
- [3.5 示例 5:深度复制在A/B测试中的应用](#3.5 示例 5:深度复制在A/B测试中的应用)
- [3.6 示例 6:CogAcqFifoTool 相机配置的保存与加载](#3.6 示例 6:CogAcqFifoTool 相机配置的保存与加载)
- [3.7 示例 7:异常处理与文件校验](#3.7 示例 7:异常处理与文件校验)
- 4.CogSerializer补充示例集
-
- [4.1 ToolBlock 输入输出连线的序列化与恢复](#4.1 ToolBlock 输入输出连线的序列化与恢复)
- [4.2 模板训练结果的持久化与复用](#4.2 模板训练结果的持久化与复用)
- [4.3 Fixture定位工具的配置持久化](#4.3 Fixture定位工具的配置持久化)
- [4.4 多相机配置管理](#4.4 多相机配置管理)
- [4.5 ToolBlock运行结果的序列化与分析](#4.5 ToolBlock运行结果的序列化与分析)
- [4.6 标定数据的保存与恢复](#4.6 标定数据的保存与恢复)
- [4.7 配置热更新(运行时动态替换)](#4.7 配置热更新(运行时动态替换))
- [4.8 ToolBlock高级脚本中的序列化应用](#4.8 ToolBlock高级脚本中的序列化应用)
- [4.9 配置版本管理与差异对比](#4.9 配置版本管理与差异对比)
- [4.10 完整的视觉检测流水线](#4.10 完整的视觉检测流水线)
- 5.相关类速查表
-
- [5.1 核心序列化相关类](#5.1 核心序列化相关类)
- [5.2 常用可序列化对象](#5.2 常用可序列化对象)
- [5.3 VisionPro工具与命名空间对照](#5.3 VisionPro工具与命名空间对照)
- [6. CogMisc实用工具方法](#6. CogMisc实用工具方法)
- 7.坐标空间特殊符号
- [8. 附录](#8. 附录)
-
- [8.1 常用using语句](#8.1 常用using语句)
- [8.2 一句话速查](#8.2 一句话速查)

1. 功能介绍
CogSerializer是VisionPro 命名空间 Cognex.VisionPro 下的静态工具类,专门用于 VisionPro 复杂对象图的深度持久化。
它不是通用的 .NET 序列化器,而是Cognex为自家库深度定制的序列化方案,能递归处理 CogToolBlock 内部包含的整套工具链、图形接口、数据绑定甚至自定义脚本中的扩展属性。
1.1 核心特性
| 特性 | 说明 |
|---|---|
| 命名空间 | Cognex.VisionPro |
| 类类型 | 静态类(不可实例化) |
| 文件格式 | .vpp |
| 序列化机制 | 基于 .NET Binary Formatter,深度定制 |
| 核心能力 | 文件/流 读写、深度复制、多粒度选项控制 |
重要版本提示 :
CogToolBlock和CogToolGroup自身的Clone()方法在构造工具间数据连接时存在缺陷------克隆对象内的工具间链接不会正确重建。康耐视官方文档明确指出克隆功能无法正常工作,并建议开发者改为使用
CogSerializer.DeepCopyObject()来实现深度复制。
2. 核心API详解
2.1 文件读写方法
2.1.1 SaveObjectToFile---保存对象到文件
csharp
public static void SaveObjectToFile(
object obj,
string path,
IFormatter formatter = null,
CogSerializationOptionsConstants options = CogSerializationOptionsConstants.Minimum
)
| 参数 | 类型 | 说明 |
|---|---|---|
obj |
object |
要保存的 VisionPro 对象(如 CogToolBlock、CogPMAlignPattern 等) |
path |
string |
目标文件路径,通常以 .vpp 为扩展名 |
formatter |
IFormatter |
序列化格式器,传 null 使用默认的 BinaryFormatter |
options |
CogSerializationOptionsConstants |
序列化粒度选项,默认 Minimum |
2.1.2 LoadObjectFromFile---从文件加载对象
csharp
public static object LoadObjectFromFile(string path)
| 参数 | 类型 | 说明 |
|---|---|---|
path |
string |
.vpp 文件路径 |
LoadObjectFromFile返回值 :object 类型,需要显式类型转换。
2.2 内存流读写方法
2.2.1 SaveObjectToStream---保存对象到内存流
csharp
public static void SaveObjectToStream(object obj, Stream stream)
2.2.2 LoadObjectFromStream---从内存流加载对象
csharp
public static object LoadObjectFromStream(Stream stream)
适用场景:内存中对象复制、多版本管理、网络传输等临时操作。
2.3 深度复制方法
2.3.1 DeepCopyObject---深度复制(官方推荐)
csharp
public static object DeepCopyObject(object obj, CogSerializationOptionsConstants optionBits)
| 参数 | 类型 | 说明 |
|---|---|---|
source |
object |
源 VisionPro 对象 |
返回值:与源对象同类型的深度副本,保留完整的内部引用关系。
关键说明 :此方法是康耐视官方推荐的替代
Clone()的方案。其内部实现等价于将对象序列化到内存流再反序列化回来,因此能正确处理复杂对象图中的交叉引用。
2.3.2 CogSerializationOptionsConstants枚举详解
此枚举定义在 Cognex.VisionPro 命名空间下,用于控制序列化的粒度。
| 枚举值 | 值 | 说明 | 适用场景 |
|---|---|---|---|
Minimum |
0 | 仅序列化必要信息,省略默认值和冗余数据 | 日常配置保存(推荐) |
All |
1 | 序列化所有信息(包括默认值) | 完整备份、调试分析 |
ExcludeDataBindings |
2 | 排除所有数据绑定信息 | 配置迁移(绑定信息在新环境下会失效) |
ExcludeGraphics |
4 | 排除所有图形(Graphics)信息 | 仅保存参数逻辑 |
2.3.2.1 选项组合使用
枚举值支持位运算组合,可以同时排除多种信息:
csharp
// 同时排除数据绑定和图形信息
var options = CogSerializationOptionsConstants.ExcludeDataBindings
| CogSerializationOptionsConstants.ExcludeGraphics;
CogSerializer.SaveObjectToFile(block, path, null, options);
2.3.2.2 选项选择建议
| 场景 | 推荐选项 | 原因 |
|---|---|---|
| 日常开发保存 | Minimum |
文件小、速度快 |
| 版本发布归档 | All |
完整保留所有信息 |
| 跨机器迁移配置 | ExcludeDataBindings |
避免绑定路径失效导致错误 |
| 仅保存算法参数 | ExcludeGraphics |
减少图形对象的序列化开销 |
| 跨版本升级 | `ExcludeDataBindings | ExcludeGraphics` |
3. 代码示例
3.1 示例 1:基本的保存与加载
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.PMAlign;
// ===== 创建并配置 ToolBlock =====
CogToolBlock block = new CogToolBlock();
block.Name = "InspectionBlock";
// 添加模板匹配工具
CogPMAlignTool pmaTool = new CogPMAlignTool();
pmaTool.Name = "PMAlign1";
block.Tools.Add(pmaTool);
// 添加更多工具并配置...
// block.Tools.Add(otherTool);
// ===== 保存到文件 =====
string savePath = @"D:\VisionConfigs\InspectionBlock.vpp";
CogSerializer.SaveObjectToFile(block, savePath);
Console.WriteLine($"配置已保存至: {savePath}");
// ===== 从文件加载 =====
CogToolBlock loadedBlock = CogSerializer.LoadObjectFromFile(savePath) as CogToolBlock;
if (loadedBlock != null)
{
Console.WriteLine($"加载成功,工具数量: {loadedBlock.Tools.Count}");
loadedBlock.Run();
}
3.2 示例 2:多粒度保存策略
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.ToolGroup;
using System.IO;
// ===== 场景 1: 保存单个模板匹配工具的 Pattern =====
CogPMAlignTool pmaTool = new CogPMAlignTool();
// ... 配置并训练 ...
CogSerializer.SaveObjectToFile(
pmaTool.Pattern,
@"D:\Patterns\MyPattern.vpp"
);
// ===== 场景 2: 保存完整 ToolGroup(带所有工具和内部连线) =====
CogToolGroup toolGroup = new CogToolGroup();
// ... 添加工具并建立连接 ...
CogSerializer.SaveObjectToFile(
toolGroup,
@"D:\Configs\FullToolGroup.vpp",
null,
CogSerializationOptionsConstants.All // 完整保存
);
// ===== 场景 3: 仅保存参数逻辑(排除图形和绑定) =====
CogSerializer.SaveObjectToFile(
toolGroup,
@"D:\Configs\ParamsOnly.vpp",
null,
CogSerializationOptionsConstants.ExcludeDataBindings
| CogSerializationOptionsConstants.ExcludeGraphics
);
// ===== 场景 4: 跨机器迁移时排除绑定信息 =====
CogSerializer.SaveObjectToFile(
toolGroup,
@"D:\Configs\MigrateSafe.vpp",
null,
CogSerializationOptionsConstants.ExcludeDataBindings
);
3.3 示例 3:使用流进行内存复制与多版本管理
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System.IO;
CogToolBlock originalBlock = CogSerializer.LoadObjectFromFile(@"D:\Configs\Block.vpp") as CogToolBlock;
// ===== 方法 1: 使用 DeepCopyObject(推荐) =====
CogToolBlock copy1 = CogSerializer.DeepCopyObject(originalBlock) as CogToolBlock;
copy1.Name = "Copy1";
// ===== 方法 2: 手动使用流 =====
using (MemoryStream ms = new MemoryStream())
{
// 保存到流
CogSerializer.SaveObjectToStream(originalBlock, ms);
// 从流加载(需要重置流位置)
ms.Position = 0;
CogToolBlock copy2 = CogSerializer.LoadObjectFromStream(ms) as CogToolBlock;
copy2.Name = "Copy2";
}
// ===== 实际应用:创建运行前/运行后快照 =====
using (MemoryStream beforeRun = new MemoryStream())
{
CogSerializer.SaveObjectToStream(originalBlock, beforeRun);
originalBlock.Run(); // 执行视觉检测
// 运行后可以对比 beforeRun 和当前状态
beforeRun.Position = 0;
CogToolBlock snapshot = CogSerializer.LoadObjectFromStream(beforeRun) as CogToolBlock;
}
3.4 示例 4:批量配置文件管理器
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// VisionPro 配置文件管理器
/// 支持批量加载、保存、备份和版本管理
/// </summary>
public class VppConfigManager
{
private readonly string _configDirectory;
private readonly string _backupDirectory;
public VppConfigManager(string configDirectory)
{
_configDirectory = configDirectory;
_backupDirectory = Path.Combine(configDirectory, "Backups");
if (!Directory.Exists(_backupDirectory))
Directory.CreateDirectory(_backupDirectory);
}
/// <summary>
/// 加载所有 .vpp 配置文件
/// </summary>
public Dictionary<string, CogToolBlock> LoadAllConfigs()
{
var configs = new Dictionary<string, CogToolBlock>();
foreach (string file in Directory.GetFiles(_configDirectory, "*.vpp"))
{
try
{
string key = Path.GetFileNameWithoutExtension(file);
CogToolBlock block = CogSerializer.LoadObjectFromFile(file) as CogToolBlock;
if (block != null)
{
configs[key] = block;
Console.WriteLine($"✓ 已加载: {key}");
}
}
catch (Exception ex)
{
Console.WriteLine($"✗ 加载失败 {Path.GetFileName(file)}: {ex.Message}");
}
}
return configs;
}
/// <summary>
/// 保存配置并自动创建备份
/// </summary>
public void SaveWithBackup(string name, CogToolBlock block)
{
string filePath = Path.Combine(_configDirectory, $"{name}.vpp");
// 如果已存在同名文件,先备份
if (File.Exists(filePath))
{
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string backupPath = Path.Combine(_backupDirectory, $"{name}_{timestamp}.vpp");
File.Copy(filePath, backupPath, true);
Console.WriteLine($"已备份至: {backupPath}");
}
// 保存新配置
CogSerializer.SaveObjectToFile(block, filePath);
Console.WriteLine($"已保存: {filePath}");
}
/// <summary>
/// 导出精简版配置(排除绑定和图形,便于迁移)
/// </summary>
public void ExportPortable(string name, CogToolBlock block)
{
string exportPath = Path.Combine(_configDirectory, $"{name}_portable.vpp");
CogSerializer.SaveObjectToFile(
block, exportPath, null,
CogSerializationOptionsConstants.ExcludeDataBindings
| CogSerializationOptionsConstants.ExcludeGraphics
);
Console.WriteLine($"已导出精简版: {exportPath}");
}
}
// 使用示例
class Program
{
static void Main()
{
var manager = new VppConfigManager(@"D:\VisionConfigs");
// 批量加载
var configs = manager.LoadAllConfigs();
// 保存并自动备份
if (configs.ContainsKey("Inspection"))
{
configs["Inspection"].Run();
manager.SaveWithBackup("Inspection", configs["Inspection"]);
manager.ExportPortable("Inspection", configs["Inspection"]);
}
}
}
3.5 示例 5:深度复制在A/B测试中的应用
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.PMAlign;
/// <summary>
/// 使用深度复制实现参数 A/B 测试
/// 在不影响原始配置的情况下对比不同参数的效果
/// </summary>
public class ParameterABTest
{
private CogToolBlock _originalBlock;
public ParameterABTest(CogToolBlock block)
{
_originalBlock = block;
}
/// <summary>
/// 对比两组参数的检测结果
/// </summary>
public void CompareParameters(
Action<CogPMAlignTool> configA,
Action<CogPMAlignTool> configB,
CogImage8Grey testImage)
{
// 深度复制两份独立的 ToolBlock
CogToolBlock blockA = CogSerializer.DeepCopyObject(_originalBlock) as CogToolBlock;
CogToolBlock blockB = CogSerializer.DeepCopyObject(_originalBlock) as CogToolBlock;
// 分别应用不同参数
CogPMAlignTool toolA = blockA.Tools["PMAlign1"] as CogPMAlignTool;
CogPMAlignTool toolB = blockB.Tools["PMAlign1"] as CogPMAlignTool;
configA?.Invoke(toolA);
configB?.Invoke(toolB);
// 设置输入图像
blockA.Inputs["Image"].Value = testImage;
blockB.Inputs["Image"].Value = testImage;
// 运行并对比
blockA.Run();
blockB.Run();
// 分析结果差异
Console.WriteLine("=== 参数 A 结果 ===");
AnalyzeResults(blockA);
Console.WriteLine("=== 参数 B 结果 ===");
AnalyzeResults(blockB);
}
private void AnalyzeResults(CogToolBlock block)
{
foreach (ICogTool tool in block.Tools)
{
if (tool.RunStatus != null)
{
Console.WriteLine($" {tool.Name}: {tool.RunStatus.Result}");
}
}
}
}
3.6 示例 6:CogAcqFifoTool 相机配置的保存与加载
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ImageFile;
// ===== 保存相机采集工具配置 =====
// 假设已在 QuickBuild 中配置好相机参数
CogAcqFifoTool acqTool = new CogAcqFifoTool();
// ... 配置相机参数(曝光、增益、触发模式等) ...
CogSerializer.SaveObjectToFile(
acqTool,
@"D:\Cameras\Camera1.vpp",
null,
CogSerializationOptionsConstants.Minimum
);
// ===== 加载相机配置到编辑控件 =====
CogAcqFifoTool loadedAcqTool =
CogSerializer.LoadObjectFromFile(@"D:\Cameras\Camera1.vpp") as CogAcqFifoTool;
if (loadedAcqTool != null)
{
// 绑定到编辑控件进行显示/修改
cogAcqFifoEditV21.Subject = loadedAcqTool;
// 或直接使用采集
loadedAcqTool.Run();
CogImage8Grey image = loadedAcqTool.OutputImage as CogImage8Grey;
}
3.7 示例 7:异常处理与文件校验
csharp
using Cognex.VisionPro;
using System;
using System.IO;
public static class SafeVppLoader
{
/// <summary>
/// 安全加载 VPP 文件,包含完整的异常处理
/// </summary>
public static T LoadSafe<T>(string filePath) where T : class
{
// 1. 文件存在性检查
if (!File.Exists(filePath))
{
Console.WriteLine($"错误: 文件不存在 - {filePath}");
return null;
}
// 2. 文件大小检查
FileInfo fi = new FileInfo(filePath);
if (fi.Length == 0)
{
Console.WriteLine($"错误: 文件为空 - {filePath}");
return null;
}
try
{
// 3. 加载并转换
object obj = CogSerializer.LoadObjectFromFile(filePath);
if (obj is T typed)
{
Console.WriteLine($"成功加载: {filePath} (类型: {typeof(T).Name})");
return typed;
}
else
{
Console.WriteLine($"类型不匹配: 期望 {typeof(T).Name}, 实际 {obj?.GetType().Name ?? "null"}");
return null;
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"权限不足: {filePath}");
}
catch (IOException ex)
{
Console.WriteLine($"IO 错误: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"加载失败: {ex.Message}");
}
return null;
}
/// <summary>
/// 安全保存 VPP 文件
/// </summary>
public static bool SaveSafe<T>(T obj, string filePath) where T : class
{
try
{
// 确保目录存在
string dir = Path.GetDirectoryName(filePath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir))
Directory.CreateDirectory(dir);
CogSerializer.SaveObjectToFile(obj, filePath);
Console.WriteLine($"保存成功: {filePath}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"保存失败: {ex.Message}");
return false;
}
}
}
// 使用示例
class Program
{
static void Main()
{
// 安全加载
var block = SafeVppLoader.LoadSafe<CogToolBlock>(@"D:\Configs\Block.vpp");
if (block != null)
{
block.Run();
}
// 安全保存
SafeVppLoader.SaveSafe(block, @"D:\Configs\Block_backup.vpp");
}
}
4.CogSerializer补充示例集
4.1 ToolBlock 输入输出连线的序列化与恢复
在实际项目中,CogToolBlock 的输入/输出终端(Terminal)定义和工具间的数据连线是核心配置。序列化时需要确保连线信息被完整保留。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.Caliper;
using System;
/// <summary>
/// 创建带完整输入输出连线的 ToolBlock,并进行序列化
/// </summary>
public class ToolBlockWiringDemo
{
/// <summary>
/// 创建一个完整的检测 ToolBlock:
/// 输入:Image (CogImage8Grey)
/// 工具链:PMAlign定位 → Fixture校正 → Caliper测量
/// 输出:ResultX, ResultY, Width, Pass
/// </summary>
public static CogToolBlock CreateInspectionBlock()
{
CogToolBlock block = new CogToolBlock();
block.Name = "InspectionBlock";
// ===== 1. 定义输入终端 =====
block.Inputs.Add(new CogToolBlockTerminal("Image", typeof(CogImage8Grey)));
// ===== 2. 添加工具 =====
// 模板匹配工具(定位)
CogPMAlignTool pmaTool = new CogPMAlignTool();
pmaTool.Name = "PMAlign_Locate";
block.Tools.Add(pmaTool);
// 定位工具(坐标校正)
CogFixtureTool fixtureTool = new CogFixtureTool();
fixtureTool.Name = "Fixture_Correct";
block.Tools.Add(fixtureTool);
// 卡尺工具(宽度测量)
CogCaliperTool caliperTool = new CogCaliperTool();
caliperTool.Name = "Caliper_Width";
block.Tools.Add(caliperTool);
// ===== 3. 建立工具间数据连线 =====
// Image → PMAlign 输入
block.Connect(block.Inputs["Image"], pmaTool, "InputImage");
// PMAlign 的输出图像 → Fixture 的输入图像
block.Connect(pmaTool, "OutputImage", fixtureTool, "InputImage");
// Fixture 的输出图像 → Caliper 的输入图像
block.Connect(fixtureTool, "OutputImage", caliperTool, "InputImage");
// ===== 4. 定义输出终端 =====
// 从 PMAlign 获取定位坐标
block.Outputs.Add(new CogToolBlockTerminal("ResultX",
pmaTool, "Results.GetPose().TranslationX"));
block.Outputs.Add(new CogToolBlockTerminal("ResultY",
pmaTool, "Results.GetPose().TranslationY"));
// 从 Caliper 获取宽度
// 注意:实际项目中需要根据 Caliper 结果的具体路径来设置
// block.Outputs.Add(new CogToolBlockTerminal("Width",
// caliperTool, "Results.Width"));
return block;
}
/// <summary>
/// 保存 ToolBlock 配置(保留所有连线信息)
/// </summary>
public static void SaveInspectionConfig(CogToolBlock block, string path)
{
// 使用 Minimum 选项即可保留连线信息
// 连线属于工具间关系,不属于 DataBinding 或 Graphics
CogSerializer.SaveObjectToFile(block, path);
Console.WriteLine($"[保存] 工具数量: {block.Tools.Count}, 输入: {block.Inputs.Count}, 输出: {block.Outputs.Count}");
}
/// <summary>
/// 加载并验证 ToolBlock 配置
/// </summary>
public static CogToolBlock LoadAndVerify(string path)
{
CogToolBlock block = CogSerializer.LoadObjectFromFile(path) as CogToolBlock;
if (block == null)
{
Console.WriteLine("[错误] 加载失败");
return null;
}
Console.WriteLine($"[加载成功] 名称: {block.Name}");
Console.WriteLine($" 工具数量: {block.Tools.Count}");
Console.WriteLine($" 输入终端: {block.Inputs.Count}");
Console.WriteLine($" 输出终端: {block.Outputs.Count}");
// 遍历所有工具检查状态
foreach (ICogTool tool in block.Tools)
{
Console.WriteLine($" 工具: {tool.Name} ({tool.GetType().Name})");
}
return block;
}
}
// 使用示例
class Program
{
static void Main()
{
string configPath = @"D:\Configs\InspectionWired.vpp";
// 创建并保存
CogToolBlock block = ToolBlockWiringDemo.CreateInspectionBlock();
ToolBlockWiringDemo.SaveInspectionConfig(block, configPath);
// 加载并验证连线
CogToolBlock loaded = ToolBlockWiringDemo.LoadAndVerify(configPath);
// 运行检测(需要先设置输入图像)
// loaded.Inputs["Image"].Value = myImage;
// loaded.Run();
}
}
4.2 模板训练结果的持久化与复用
CogPMAlignTool 的 Pattern(模板)训练是一个耗时操作,通常在开发阶段完成训练后保存,运行阶段直接加载。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.PMAlign;
using System;
using System.IO;
/// <summary>
/// 模板管理器:支持训练、保存、加载、版本管理
/// </summary>
public class PatternManager
{
private readonly string _patternDir;
public PatternManager(string patternDirectory)
{
_patternDir = patternDirectory;
if (!Directory.Exists(_patternDir))
Directory.CreateDirectory(_patternDir);
}
/// <summary>
/// 训练并保存模板
/// </summary>
public bool TrainAndSave(string patternName, CogImage8Grey trainImage,
CogPMAlignPattern.PatternTypeConstants patternType = CogPMAlignPattern.PatternTypeConstants.PatMax)
{
try
{
CogPMAlignTool tool = new CogPMAlignTool();
tool.Pattern.TrainImage = trainImage;
tool.Pattern.TrainImageTransform = new CogTransform2DRigid();
tool.Pattern.Origin.TranslationX = trainImage.Width / 2.0;
tool.Pattern.Origin.TranslationY = trainImage.Height / 2.0;
// 设置匹配类型
tool.Pattern.PatternType = patternType;
// 执行训练
tool.Pattern.Train();
if (!tool.Pattern.Trained)
{
Console.WriteLine($"[错误] 模板训练失败: {patternName}");
return false;
}
// 保存整个工具(包含 Pattern)
string toolPath = Path.Combine(_patternDir, $"{patternName}_tool.vpp");
CogSerializer.SaveObjectToFile(tool, toolPath);
// 也可以单独保存 Pattern
string patternPath = Path.Combine(_patternDir, $"{patternName}_pattern.vpp");
CogSerializer.SaveObjectToFile(tool.Pattern, patternPath);
Console.WriteLine($"[成功] 模板已训练并保存: {patternName}");
Console.WriteLine($" 特征点数: {tool.Pattern.NumTrainedPoints}");
Console.WriteLine($" 工具文件: {toolPath}");
Console.WriteLine($" 模板文件: {patternPath}");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"[异常] {ex.Message}");
return false;
}
}
/// <summary>
/// 加载已保存的模板到工具
/// </summary>
public CogPMAlignTool LoadPattern(string patternName)
{
string toolPath = Path.Combine(_patternDir, $"{patternName}_tool.vpp");
if (!File.Exists(toolPath))
{
// 尝试单独加载 Pattern
string patternPath = Path.Combine(_patternDir, $"{patternName}_pattern.vpp");
if (File.Exists(patternPath))
{
CogPMAlignPattern pattern = CogSerializer.LoadObjectFromFile(patternPath) as CogPMAlignPattern;
if (pattern != null)
{
CogPMAlignTool tool = new CogPMAlignTool();
tool.Pattern = pattern;
Console.WriteLine($"[加载] 单独模板: {patternName}");
return tool;
}
}
Console.WriteLine($"[未找到] 模板: {patternName}");
return null;
}
CogPMAlignTool loadedTool = CogSerializer.LoadObjectFromFile(toolPath) as CogPMAlignTool;
if (loadedTool != null)
{
Console.WriteLine($"[加载] 完整工具: {patternName}, 训练状态: {loadedTool.Pattern.Trained}");
}
return loadedTool;
}
/// <summary>
/// 列出所有已保存的模板
/// </summary>
public void ListPatterns()
{
Console.WriteLine("=== 已保存的模板 ===");
foreach (string file in Directory.GetFiles(_patternDir, "*_tool.vpp"))
{
string name = Path.GetFileNameWithoutExtension(file).Replace("_tool", "");
FileInfo fi = new FileInfo(file);
Console.WriteLine($" {name} - {fi.LastWriteTime:yyyy-MM-dd HH:mm} - {fi.Length / 1024}KB");
}
}
}
// 使用示例
class Program
{
static void Main()
{
var mgr = new PatternManager(@"D:\Patterns");
// 训练模板(首次)
CogImage8Grey trainImage = LoadImage(); // 你的图像加载方法
mgr.TrainAndSave("Connector_Pin", trainImage);
// 后续直接加载
CogPMAlignTool tool = mgr.LoadPattern("Connector_Pin");
if (tool != null)
{
tool.InputImage = LoadRuntimeImage();
tool.Run();
if (tool.Results != null && tool.Results.Count > 0)
{
Console.WriteLine($"匹配成功: X={tool.Results[0].Pose.TranslationX:F2}, " +
$"Y={tool.Results[0].Pose.TranslationY:F2}, " +
$"Score={tool.Results[0].Score:F4}");
}
}
}
}
4.3 Fixture定位工具的配置持久化
CogFixtureTool用于坐标空间变换,在多工位检测中非常常见。其配置(原点、角度、比例)需要持久化。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.CalibFix;
using Cognex.VisionPro.PMAlign;
using System;
/// <summary>
/// 定位工具配置管理
/// 支持保存/加载 Fixture 配置,以及基于 PMAlign 结果动态更新
/// </summary>
public class FixtureConfigManager
{
/// <summary>
/// 创建基于 PMAlign 结果的 Fixture 配置
/// </summary>
public static CogFixtureTool CreateFixtureFromPMAlign(
CogPMAlignTool pmaTool, string fixtureName = "Fixture1")
{
CogFixtureTool fixture = new CogFixtureTool();
fixture.Name = fixtureName;
// 设置 Fixture 的工作模式
fixture.RunParams.UnfixturedImageFixturedImageSpaceNameChange =
CogFixtureToolFixedImageSpaceNameChangeConstants.FixedImageName;
// 如果 PMAlign 已运行且有结果,基于其位姿设置 Fixture
if (pmaTool.Results != null && pmaTool.Results.Count > 0)
{
fixture.RunParams.FixturedTransformName = "Fixture";
fixture.RunParams.TrainImage = pmaTool.Results[0].GetPose();
// 使用 PMAlign 的输出图像作为 Fixture 输入
fixture.InputImage = pmaTool.OutputImage;
}
return fixture;
}
/// <summary>
/// 保存 Fixture 配置
/// </summary>
public static void SaveFixture(CogFixtureTool fixture, string path)
{
CogSerializer.SaveObjectToFile(fixture, path);
Console.WriteLine($"[保存] Fixture: {fixture.Name}");
Console.WriteLine($" 变换名称: {fixture.RunParams.FixturedTransformName}");
}
/// <summary>
/// 加载 Fixture 配置
/// </summary>
public static CogFixtureTool LoadFixture(string path)
{
CogFixtureTool fixture = CogSerializer.LoadObjectFromFile(path) as CogFixtureTool;
if (fixture != null)
{
Console.WriteLine($"[加载] Fixture: {fixture.Name}");
Console.WriteLine($" 变换名称: {fixture.RunParams.FixturedTransformName}");
}
return fixture;
}
/// <summary>
/// 保存完整的定位+检测流程
/// </summary>
public static void SaveFixtureWorkflow(
CogPMAlignTool pmaTool, CogFixtureTool fixture, string dir)
{
// 分别保存各工具
CogSerializer.SaveObjectToFile(pmaTool, System.IO.Path.Combine(dir, "PMAlign.vpp"));
CogSerializer.SaveObjectToFile(fixture, System.IO.Path.Combine(dir, "Fixture.vpp"));
// 也可以用 ToolBlock 打包保存
CogToolBlock block = new CogToolBlock();
block.Name = "FixtureWorkflow";
block.Tools.Add(CogSerializer.DeepCopyObject(pmaTool));
block.Tools.Add(CogSerializer.DeepCopyObject(fixture));
CogSerializer.SaveObjectToFile(block, System.IO.Path.Combine(dir, "Workflow.vpp"));
Console.WriteLine("[保存] 定位流程已保存(单独文件 + 整合包)");
}
}
4.4 多相机配置管理
在多相机系统中,每台相机的参数(曝光、增益、触发模式)不同,需要独立保存和管理。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System;
using System.Collections.Generic;
using System.IO;
/// <summary>
/// 多相机配置管理器
/// </summary>
public class MultiCameraConfigManager
{
private readonly string _configRoot;
private readonly Dictionary<string, CogAcqFifoTool> _cameras = new Dictionary<string, CogAcqFifoTool>();
public MultiCameraConfigManager(string configRoot)
{
_configRoot = configRoot;
}
/// <summary>
/// 保存单台相机配置
/// </summary>
public void SaveCameraConfig(string cameraName, CogAcqFifoTool acqTool)
{
string cameraDir = Path.Combine(_configRoot, cameraName);
if (!Directory.Exists(cameraDir))
Directory.CreateDirectory(cameraDir);
string path = Path.Combine(cameraDir, "Camera.vpp");
CogSerializer.SaveObjectToFile(acqTool, path);
// 同时保存一份备份
string backupDir = Path.Combine(cameraDir, "Backup");
if (!Directory.Exists(backupDir))
Directory.CreateDirectory(backupDir);
string backupPath = Path.Combine(backupDir, $"Camera_{DateTime.Now:yyyyMMdd_HHmmss}.vpp");
File.Copy(path, backupPath, true);
_cameras[cameraName] = acqTool;
Console.WriteLine($"[保存] 相机 {cameraName} 配置已保存");
}
/// <summary>
/// 加载单台相机配置
/// </summary>
public CogAcqFifoTool LoadCameraConfig(string cameraName)
{
string path = Path.Combine(_configRoot, cameraName, "Camera.vpp");
if (!File.Exists(path))
{
Console.WriteLine($"[未找到] 相机 {cameraName} 配置文件");
return null;
}
CogAcqFifoTool acqTool = CogSerializer.LoadObjectFromFile(path) as CogAcqFifoTool;
if (acqTool != null)
{
_cameras[cameraName] = acqTool;
Console.WriteLine($"[加载] 相机 {cameraName} 配置已加载");
}
return acqTool;
}
/// <summary>
/// 加载所有相机配置
/// </summary>
public void LoadAllCameras()
{
if (!Directory.Exists(_configRoot))
{
Console.WriteLine("[错误] 配置目录不存在");
return;
}
foreach (string cameraDir in Directory.GetDirectories(_configRoot))
{
string cameraName = Path.GetFileName(cameraDir);
if (cameraName == "Backup") continue;
LoadCameraConfig(cameraName);
}
Console.WriteLine($"[完成] 共加载 {_cameras.Count} 台相机配置");
}
/// <summary>
/// 创建多相机 ToolBlock(含所有相机的采集工具)
/// </summary>
public CogToolBlock CreateMultiCameraBlock()
{
CogToolBlock block = new CogToolBlock();
block.Name = "MultiCamera";
foreach (var kvp in _cameras)
{
// 深度复制,避免修改原始配置
CogAcqFifoTool copy = CogSerializer.DeepCopyObject(kvp.Value) as CogAcqFifoTool;
copy.Name = $"Acq_{kvp.Key}";
block.Tools.Add(copy);
// 添加输出终端
block.Outputs.Add(new CogToolBlockTerminal($"{kvp.Key}_Image",
copy, "OutputImage"));
}
return block;
}
/// <summary>
/// 列出所有相机
/// </summary>
public void ListCameras()
{
Console.WriteLine("=== 相机列表 ===");
foreach (var kvp in _cameras)
{
Console.WriteLine($" {kvp.Key}: {kvp.Value.GetType().Name}");
}
}
}
// 使用示例
class Program
{
static void Main()
{
var mgr = new MultiCameraConfigManager(@"D:\Cameras");
// 首次配置并保存
CogAcqFifoTool cam1 = new CogAcqFifoTool();
// ... 配置相机1参数 ...
mgr.SaveCameraConfig("TopCamera", cam1);
CogAcqFifoTool cam2 = new CogAcqFifoTool();
// ... 配置相机2参数 ...
mgr.SaveCameraConfig("SideCamera", cam2);
// 后续直接加载
mgr.LoadAllCameras();
mgr.ListCameras();
// 创建多相机 ToolBlock
CogToolBlock multiCam = mgr.CreateMultiCameraBlock();
CogSerializer.SaveObjectToFile(multiCam, @"D:\Configs\MultiCamera.vpp");
}
}
4.5 ToolBlock运行结果的序列化与分析
将ToolBlock的运行结果(包括状态、输出值、图形标注)保存下来,用于离线分析和质量追溯。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System;
using System.IO;
/// <summary>
/// 运行结果快照:保存 ToolBlock 运行前后的完整状态
/// </summary>
public class RunResultSnapshot
{
public string Timestamp { get; set; }
public string BlockName { get; set; }
public CogToolResultConstants OverallResult { get; set; }
public CogToolBlock BlockSnapshot { get; set; } // 运行后的 Block 副本
public override string ToString()
{
return $"[{Timestamp}] {BlockName} => {OverallResult}";
}
}
/// <summary>
/// 运行结果管理器:支持结果保存、加载、批量分析
/// </summary>
public class RunResultManager
{
private readonly string _resultDir;
private int _sequence = 0;
public RunResultManager(string resultDirectory)
{
_resultDir = resultDirectory;
if (!Directory.Exists(_resultDir))
Directory.CreateDirectory(_resultDir);
}
/// <summary>
/// 运行 ToolBlock 并保存结果快照
/// </summary>
public RunResultSnapshot RunAndCapture(CogToolBlock block, object inputImage = null)
{
// 设置输入
if (inputImage != null && block.Inputs.Count > 0)
{
block.Inputs[0].Value = inputImage;
}
// 运行前快照(使用流)
MemoryStream beforeSnapshot = new MemoryStream();
CogSerializer.SaveObjectToStream(block, beforeSnapshot);
// 执行运行
block.Run();
// 运行后深度复制
CogToolBlock afterSnapshot = CogSerializer.DeepCopyObject(block) as CogToolBlock;
_sequence++;
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
var result = new RunResultSnapshot
{
Timestamp = timestamp,
BlockName = block.Name,
OverallResult = block.RunStatus.Result,
BlockSnapshot = afterSnapshot
};
// 保存到文件
string filePath = Path.Combine(_resultDir, $"Run_{_sequence:D6}_{timestamp}.vpp");
CogSerializer.SaveObjectToFile(afterSnapshot, filePath);
Console.WriteLine($"[运行 #{_sequence}] {result}");
// 清理
beforeSnapshot.Dispose();
return result;
}
/// <summary>
/// 加载历史运行结果
/// </summary>
public RunResultSnapshot LoadResult(string filePath)
{
CogToolBlock block = CogSerializer.LoadObjectFromFile(filePath) as CogToolBlock;
if (block == null) return null;
return new RunResultSnapshot
{
Timestamp = File.GetLastWriteTime(filePath).ToString("yyyy-MM-dd HH:mm:ss"),
BlockName = block.Name,
OverallResult = block.RunStatus?.Result ?? CogToolResultConstants.Error,
BlockSnapshot = block
};
}
/// <summary>
/// 批量加载并统计运行结果
/// </summary>
public void AnalyzeHistory()
{
var files = Directory.GetFiles(_resultDir, "Run_*.vpp");
int total = 0, pass = 0, fail = 0, error = 0;
Console.WriteLine($"=== 历史运行分析 ({files.Length} 条记录) ===");
foreach (string file in files)
{
try
{
var result = LoadResult(file);
if (result == null) continue;
total++;
switch (result.OverallResult)
{
case CogToolResultConstants.Accept: pass++; break;
case CogToolResultConstants.Reject: fail++; break;
default: error++; break;
}
}
catch (Exception ex)
{
Console.WriteLine($" 加载失败 {Path.GetFileName(file)}: {ex.Message}");
error++;
}
}
Console.WriteLine($" 总计: {total}, 通过: {pass}, 失败: {fail}, 异常: {error}");
Console.WriteLine($" 通过率: {(total > 0 ? (double)pass / total * 100 : 0):F1}%");
}
/// <summary>
/// 清理旧结果(保留最近 N 条)
/// </summary>
public void Cleanup(int keepCount = 1000)
{
var files = Directory.GetFiles(_resultDir, "Run_*.vpp");
if (files.Length <= keepCount) return;
Array.Sort(files, (a, b) => File.GetLastWriteTime(a).CompareTo(File.GetLastWriteTime(b)));
int deleteCount = files.Length - keepCount;
for (int i = 0; i < deleteCount; i++)
{
File.Delete(files[i]);
}
Console.WriteLine($"[清理] 删除 {deleteCount} 条旧记录,保留 {keepCount} 条");
}
}
4.6 标定数据的保存与恢复
相机标定(CogCalibNPointToNPointTool 或 CogCalibCheckerboardTool)的配置需要持久化,以便在系统重启后快速恢复。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.CalibFix;
using System;
/// <summary>
/// 标定数据管理:保存和恢复标定配置
/// </summary>
public class CalibrationManager
{
/// <summary>
/// 保存 N 点标定工具配置
/// </summary>
public static void SaveNPointCalibration(
CogCalibNPointToNPointTool calibTool, string path)
{
CogSerializer.SaveObjectToFile(calibTool, path);
Console.WriteLine($"[保存] N点标定: {path}");
Console.WriteLine($" 已标定: {calibTool.Calibration.NumPoints} 点");
}
/// <summary>
/// 加载 N 点标定工具配置
/// </summary>
public static CogCalibNPointToNPointTool LoadNPointCalibration(string path)
{
CogCalibNPointToNPointTool calibTool =
CogSerializer.LoadObjectFromFile(path) as CogCalibNPointToNPointTool;
if (calibTool != null)
{
Console.WriteLine($"[加载] N点标定: {path}");
Console.WriteLine($" 已标定: {calibTool.Calibration.NumPoints} 点");
}
return calibTool;
}
/// <summary>
/// 保存棋盘格标定工具配置
/// </summary>
public static void SaveCheckerboardCalibration(
CogCalibCheckerboardTool calibTool, string path)
{
CogSerializer.SaveObjectToFile(calibTool, path);
Console.WriteLine($"[保存] 棋盘格标定: {path}");
}
/// <summary>
/// 加载棋盘格标定工具配置
/// </summary>
public static CogCalibCheckerboardTool LoadCheckerboardCalibration(string path)
{
CogCalibCheckerboardTool calibTool =
CogSerializer.LoadObjectFromFile(path) as CogCalibCheckerboardTool;
if (calibTool != null)
{
Console.WriteLine($"[加载] 棋盘格标定: {path}");
}
return calibTool;
}
/// <summary>
/// 创建包含标定的完整检测流程
/// </summary>
public static CogToolBlock CreateCalibratedInspection(
CogCalibNPointToNPointTool calibTool, CogToolBlock inspectionBlock)
{
CogToolBlock calibratedBlock = new CogToolBlock();
calibratedBlock.Name = "CalibratedInspection";
// 添加标定工具
calibratedBlock.Tools.Add(CogSerializer.DeepCopyObject(calibTool));
// 添加检测工具
calibratedBlock.Tools.Add(CogSerializer.DeepCopyObject(inspectionBlock));
// 连线:标定输出图像 → 检测输入图像
// (实际连线需根据具体工具接口设置)
return calibratedBlock;
}
}
4.7 配置热更新(运行时动态替换)
在不停机的情况下,动态加载新的检测配置并替换当前运行的 ToolBlock。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System;
using System.IO;
using System.Threading;
/// <summary>
/// 配置热更新管理器
/// 支持文件监控和运行时配置替换
/// </summary>
public class HotReloadManager : IDisposable
{
private CogToolBlock _activeBlock;
private readonly string _configPath;
private FileSystemWatcher _watcher;
private readonly object _lock = new object();
private DateTime _lastLoadTime = DateTime.MinValue;
public event Action<string> OnConfigReloaded;
public HotReloadManager(string configPath)
{
_configPath = configPath;
// 加载初始配置
ReloadConfig();
// 设置文件监控
string dir = Path.GetDirectoryName(configPath);
string fileName = Path.GetFileName(configPath);
_watcher = new FileSystemWatcher(dir, fileName);
_watcher.Changed += OnFileChanged;
_watcher.EnableRaisingEvents = true;
Console.WriteLine($"[热更新] 已启动监控: {configPath}");
}
/// <summary>
/// 获取当前活跃的 ToolBlock(线程安全)
/// </summary>
public CogToolBlock ActiveBlock
{
get
{
lock (_lock)
{
return _activeBlock;
}
}
}
/// <summary>
/// 运行当前配置
/// </summary>
public void Run(object inputImage = null)
{
lock (_lock)
{
if (_activeBlock == null)
{
Console.WriteLine("[错误] 无可用配置");
return;
}
if (inputImage != null && _activeBlock.Inputs.Count > 0)
{
_activeBlock.Inputs[0].Value = inputImage;
}
_activeBlock.Run();
}
}
private void OnFileChanged(object sender, FileSystemEventArgs e)
{
// 延迟加载,避免文件写入未完成
Thread.Sleep(500);
ReloadConfig();
}
private void ReloadConfig()
{
try
{
// 防止重复加载
if (File.Exists(_configPath))
{
DateTime lastWrite = File.GetLastWriteTime(_configPath);
if (lastWrite <= _lastLoadTime) return;
_lastLoadTime = lastWrite;
}
CogToolBlock newBlock = CogSerializer.LoadObjectFromFile(_configPath) as CogToolBlock;
if (newBlock == null)
{
Console.WriteLine("[警告] 配置加载失败");
return;
}
lock (_lock)
{
_activeBlock = newBlock;
}
Console.WriteLine($"[热更新] 配置已重新加载: {newBlock.Name}, 工具数: {newBlock.Tools.Count}");
OnConfigReloaded?.Invoke(_configPath);
}
catch (Exception ex)
{
Console.WriteLine($"[热更新错误] {ex.Message}");
}
}
public void Dispose()
{
_watcher?.Dispose();
}
}
// 使用示例
class Program
{
static void Main()
{
string configPath = @"D:\Configs\LiveInspection.vpp";
using (var hotReload = new HotReloadManager(configPath))
{
hotReload.OnConfigReloaded += path =>
{
Console.WriteLine($" => 配置已更新: {path}");
};
// 模拟持续运行
while (true)
{
hotReload.Run(); // 始终使用最新配置
Thread.Sleep(100);
}
}
}
}
4.8 ToolBlock高级脚本中的序列化应用
在ToolBlock脚本中使用CogSerializer实现动态配置切换和结果保存。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.Caliper;
using Cognex.VisionPro.Dimensioning;
using System;
using System.Drawing;
/// <summary>
/// ToolBlock 高级脚本示例:
/// 在脚本中实现配置动态加载和结果图形标注
///
/// 继承自 CogToolBlockAdvancedScriptBase
/// </summary>
public class AdvancedScriptDemo : CogToolBlockAdvancedScriptBase
{
private CogToolBlock mToolBlock;
// 工具引用
private CogFindCircleTool[] findCircle = new CogFindCircleTool[2];
private CogDistanceCircleCircleTool distanceTool;
// 结果显示
private CogGraphicLabel[] labels = new CogGraphicLabel[4];
/// <summary>
/// 初始化:获取工具引用
/// </summary>
public override void Initialize(CogToolGroup host)
{
base.Initialize(host);
mToolBlock = (CogToolBlock)host;
// 获取工具引用
findCircle[0] = mToolBlock.Tools["CogFindCircleTool1"] as CogFindCircleTool;
findCircle[1] = mToolBlock.Tools["CogFindCircleTool2"] as CogFindCircleTool;
distanceTool = mToolBlock.Tools["CogDistanceCircleCircleTool1"] as CogDistanceCircleCircleTool;
}
/// <summary>
/// 运行所有工具并分析结果
/// </summary>
public override bool GroupRun(ref string message, ref CogToolResultConstants result)
{
// 依次运行所有工具
foreach (ICogTool tool in mToolBlock.Tools)
{
mToolBlock.RunTool(tool, ref message, ref result);
}
// 获取结果
double radius0 = Math.Round(findCircle[0].Results.GetCircle().Radius, 2);
double radius1 = Math.Round(findCircle[1].Results.GetCircle().Radius, 2);
double distance = Math.Round(distanceTool.Distance, 2);
// 判断合格/不合格
bool isPass = (distance >= 129.5 && distance <= 130.5);
// 创建结果标签
labels[0] = CreateLabel(findCircle[0].Results.GetCircle().CenterX,
findCircle[0].Results.GetCircle().CenterY + 30,
radius0.ToString(), Color.Green);
labels[1] = CreateLabel(findCircle[1].Results.GetCircle().CenterX,
findCircle[1].Results.GetCircle().CenterY + 30,
radius1.ToString(), Color.Green);
labels[2] = CreateLabel(0, -20, distance.ToString(),
isPass ? Color.Green : Color.Red);
labels[3] = CreateLabel(0, -70, isPass ? "OK" : "NG",
isPass ? Color.Green : Color.Red);
// 设置整体结果
result = isPass ? CogToolResultConstants.Accept : CogToolResultConstants.Reject;
return false; // 返回 false,由用户控制后续流程
}
/// <summary>
/// 在运行记录中添加图形标注
/// </summary>
public override void ModifyLastRunRecord(ICogRecord lastRecord)
{
string recordPath = "CogFixtureTool1.OutputImage";
foreach (var label in labels)
{
if (label != null)
{
mToolBlock.AddGraphicToRunRecord(label, lastRecord, recordPath, "Script");
}
}
}
/// <summary>
/// 辅助方法:创建图形标签
/// </summary>
private CogGraphicLabel CreateLabel(double x, double y, string text, Color color)
{
CogGraphicLabel label = new CogGraphicLabel();
label.Font = new Font("Arial", 12);
label.Color = color == Color.Green ? CogColorConstants.Green : CogColorConstants.Red;
label.SetXYText(x, y, text);
return label;
}
}
4.9 配置版本管理与差异对比
实现配置文件的版本控制,支持版本回退和配置差异对比。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
/// <summary>
/// 配置版本管理器
/// </summary>
public class ConfigVersionManager
{
private readonly string _configDir;
private readonly string _versionDir;
public ConfigVersionManager(string configDirectory)
{
_configDir = configDirectory;
_versionDir = Path.Combine(configDirectory, ".versions");
if (!Directory.Exists(_versionDir))
Directory.CreateDirectory(_versionDir);
}
/// <summary>
/// 保存配置并创建版本记录
/// </summary>
public void SaveWithVersion(string configName, CogToolBlock block, string commitMessage = "")
{
string configPath = Path.Combine(_configDir, $"{configName}.vpp");
// 读取当前版本号
int version = GetLatestVersion(configName) + 1;
// 保存主配置
CogSerializer.SaveObjectToFile(block, configPath);
// 保存版本快照
string versionPath = Path.Combine(_versionDir, $"{configName}_v{version:D4}.vpp");
CogSerializer.SaveObjectToFile(block, versionPath);
// 记录版本信息
string infoPath = Path.Combine(_versionDir, $"{configName}_v{version:D4}.txt");
File.WriteAllText(infoPath, $"版本: {version}\n" +
$"时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}\n" +
$"说明: {commitMessage}\n" +
$"工具数: {block.Tools.Count}\n");
Console.WriteLine($"[版本 v{version}] {configName} - {commitMessage}");
}
/// <summary>
/// 获取最新版本号
/// </summary>
private int GetLatestVersion(string configName)
{
var files = Directory.GetFiles(_versionDir, $"{configName}_v????.vpp");
if (files.Length == 0) return 0;
return files.Select(f =>
{
string name = Path.GetFileNameWithoutExtension(f);
string verStr = name.Split('_').Last().TrimStart('v');
return int.TryParse(verStr, out int v) ? v : 0;
}).Max();
}
/// <summary>
/// 回退到指定版本
/// </summary>
public CogToolBlock RevertToVersion(string configName, int version)
{
string versionPath = Path.Combine(_versionDir, $"{configName}_v{version:D4}.vpp");
if (!File.Exists(versionPath))
{
Console.WriteLine($"[错误] 版本 v{version} 不存在");
return null;
}
CogToolBlock block = CogSerializer.LoadObjectFromFile(versionPath) as CogToolBlock;
if (block != null)
{
// 覆盖主配置
string configPath = Path.Combine(_configDir, $"{configName}.vpp");
CogSerializer.SaveObjectToFile(block, configPath);
Console.WriteLine($"[回退] {configName} 已回退到 v{version}");
}
return block;
}
/// <summary>
/// 列出所有版本
/// </summary>
public void ListVersions(string configName)
{
Console.WriteLine($"=== {configName} 版本历史 ===");
var files = Directory.GetFiles(_versionDir, $"{configName}_v????.vpp")
.OrderBy(f => f).ToArray();
foreach (string file in files)
{
string name = Path.GetFileNameWithoutExtension(file);
string verStr = name.Split('_').Last();
string infoPath = Path.ChangeExtension(file, ".txt");
string info = File.Exists(infoPath) ? File.ReadAllText(infoPath).Split('\n').Skip(3).FirstOrDefault() : "";
FileInfo fi = new FileInfo(file);
Console.WriteLine($" {verStr} | {fi.LastWriteTime:yyyy-MM-dd HH:mm} | {fi.Length / 1024}KB | {info}");
}
}
/// <summary>
/// 对比两个版本的工具差异
/// </summary>
public void DiffVersions(string configName, int versionA, int versionB)
{
string pathA = Path.Combine(_versionDir, $"{configName}_v{versionA:D4}.vpp");
string pathB = Path.Combine(_versionDir, $"{configName}_v{versionB:D4}.vpp");
CogToolBlock blockA = CogSerializer.LoadObjectFromFile(pathA) as CogToolBlock;
CogToolBlock blockB = CogSerializer.LoadObjectFromFile(pathB) as CogToolBlock;
if (blockA == null || blockB == null)
{
Console.WriteLine("[错误] 无法加载版本进行对比");
return;
}
Console.WriteLine($"=== 版本对比: v{versionA} vs v{versionB} ===");
// 对比工具列表
var toolsA = blockA.Tools.Cast<ICogTool>().Select(t => t.Name).ToHashSet();
var toolsB = blockB.Tools.Cast<ICogTool>().Select(t => t.Name).ToHashSet();
var added = toolsB.Except(toolsA);
var removed = toolsA.Except(toolsB);
var common = toolsA.Intersect(toolsB);
if (added.Any()) Console.WriteLine($" 新增工具: {string.Join(", ", added)}");
if (removed.Any()) Console.WriteLine($" 移除工具: {string.Join(", ", removed)}");
Console.WriteLine($" 共有工具: {common.Count()}");
// 对比输入输出
Console.WriteLine($" 输入终端: v{versionA}={blockA.Inputs.Count}, v{versionB}={blockB.Inputs.Count}");
Console.WriteLine($" 输出终端: v{versionA}={blockA.Outputs.Count}, v{versionB}={blockB.Outputs.Count}");
}
/// <summary>
/// 清理旧版本(保留最近 N 个版本)
/// </summary>
public void CleanupVersions(string configName, int keepCount = 20)
{
var files = Directory.GetFiles(_versionDir, $"{configName}_v????.vpp")
.OrderBy(f => f).ToArray();
if (files.Length <= keepCount) return;
int deleteCount = files.Length - keepCount;
for (int i = 0; i < deleteCount; i++)
{
File.Delete(files[i]);
string infoPath = Path.ChangeExtension(files[i], ".txt");
if (File.Exists(infoPath)) File.Delete(infoPath);
}
Console.WriteLine($"[清理] 删除 {deleteCount} 个旧版本,保留最近 {keepCount} 个");
}
}
4.10 完整的视觉检测流水线
将以上所有Demo整合为一个完整的视觉检测流水线,展示 CogSerializer在真实项目中的全流程应用。
csharp
using Cognex.VisionPro;
using Cognex.VisionPro.ToolBlock;
using Cognex.VisionPro.PMAlign;
using Cognex.VisionPro.Caliper;
using Cognex.VisionPro.CalibFix;
using Cognex.VisionPro.Blob;
using Cognex.VisionPro.ImageFile;
using System;
using System.IO;
/// <summary>
/// 完整视觉检测流水线
/// 整合:标定、定位、测量、检测、结果管理
/// </summary>
public class VisionPipeline
{
private readonly string _rootDir;
private CogToolBlock _pipeline;
private ConfigVersionManager _versionMgr;
private RunResultManager _resultMgr;
public VisionPipeline(string rootDir)
{
_rootDir = rootDir;
_versionMgr = new ConfigVersionManager(Path.Combine(rootDir, "Configs"));
_resultMgr = new RunResultManager(Path.Combine(rootDir, "Results"));
}
/// <summary>
/// 初始化流水线(首次创建配置)
/// </summary>
public void Initialize()
{
_pipeline = new CogToolBlock();
_pipeline.Name = "MainPipeline";
// 1. 定义输入
_pipeline.Inputs.Add(new CogToolBlockTerminal("Image", typeof(CogImage8Grey)));
// 2. 添加定位工具
CogPMAlignTool locator = new CogPMAlignTool();
locator.Name = "Locator";
_pipeline.Tools.Add(locator);
// 3. 添加定位工具
CogFixtureTool fixture = new CogFixtureTool();
fixture.Name = "Fixture";
_pipeline.Tools.Add(fixture);
// 4. 添加测量工具
CogCaliperTool caliper = new CogCaliperTool();
caliper.Name = "WidthMeasure";
_pipeline.Tools.Add(caliper);
// 5. 添加检测工具
CogBlobTool blob = new CogBlobTool();
blob.Name = "DefectCheck";
_pipeline.Tools.Add(blob);
// 6. 建立连线
// (简化示例,实际需根据具体接口设置)
// 7. 定义输出
_pipeline.Outputs.Add(new CogToolBlockTerminal("Pass", typeof(bool)));
// 保存初始版本
_versionMgr.SaveWithVersion("Pipeline", _pipeline, "初始版本");
Console.WriteLine("[初始化] 流水线已创建");
}
/// <summary>
/// 加载已有配置
/// </summary>
public bool Load()
{
string configPath = Path.Combine(_rootDir, "Configs", "Pipeline.vpp");
if (!File.Exists(configPath))
{
Console.WriteLine("[提示] 配置不存在,将初始化新配置");
Initialize();
return true;
}
_pipeline = CogSerializer.LoadObjectFromFile(configPath) as CogToolBlock;
if (_pipeline == null)
{
Console.WriteLine("[错误] 配置加载失败");
return false;
}
Console.WriteLine($"[加载] 流水线: {_pipeline.Name}, 工具数: {_pipeline.Tools.Count}");
return true;
}
/// <summary>
/// 运行检测
/// </summary>
public bool Inspect(CogImage8Grey image)
{
if (_pipeline == null)
{
Console.WriteLine("[错误] 流水线未初始化");
return false;
}
// 运行并捕获结果
var snapshot = _resultMgr.RunAndCapture(_pipeline, image);
bool pass = snapshot.OverallResult == CogToolResultConstants.Accept;
Console.WriteLine($"[检测] 结果: {(pass ? "PASS" : "FAIL")}");
return pass;
}
/// <summary>
/// 更新配置(带版本管理)
/// </summary>
public void UpdateConfig(CogToolBlock newConfig, string reason)
{
_pipeline = newConfig;
_versionMgr.SaveWithVersion("Pipeline", _pipeline, reason);
Console.WriteLine($"[更新] 配置已更新: {reason}");
}
/// <summary>
/// 回退配置
/// </summary>
public void RevertConfig(int version)
{
_pipeline = _versionMgr.RevertToVersion("Pipeline", version);
}
/// <summary>
/// 导出配置(用于部署到其他设备)
/// </summary>
public void ExportForDeployment(string exportPath)
{
CogSerializer.SaveObjectToFile(_pipeline, exportPath, null,
CogSerializationOptionsConstants.ExcludeDataBindings);
Console.WriteLine($"[导出] 配置已导出: {exportPath}");
}
/// <summary>
/// 查看历史
/// </summary>
public void ShowHistory()
{
_versionMgr.ListVersions("Pipeline");
Console.WriteLine();
_resultMgr.AnalyzeHistory();
}
/// <summary>
/// 清理旧数据
/// </summary>
public void Cleanup()
{
_versionMgr.CleanupVersions("Pipeline", keepCount: 20);
_resultMgr.Cleanup(keepCount: 1000);
}
}
// ===== 主程序 =====
class Program
{
static void Main()
{
var pipeline = new VisionPipeline(@"D:\VisionSystem");
// 加载或初始化
if (!pipeline.Load())
{
pipeline.Initialize();
}
// 模拟检测
CogImage8Grey testImage = new CogImage8Grey(640, 480);
for (int i = 0; i < 10; i++)
{
pipeline.Inspect(testImage);
}
// 查看历史
pipeline.ShowHistory();
// 导出部署
pipeline.ExportForDeployment(@"D:\Export\Pipeline_deploy.vpp");
// 清理
pipeline.Cleanup();
}
}
5.相关类速查表
5.1 核心序列化相关类
| 类名 | 命名空间 | 说明 |
|---|---|---|
CogSerializer |
Cognex.VisionPro |
序列化主类 |
CogSerializationOptionsConstants |
Cognex.VisionPro |
序列化选项枚举 |
CogSerializationOptionsAttribute |
Cognex.VisionPro |
标记字段的可选序列化属性 |
CogSerializationDataBindingAttribute |
Cognex.VisionPro |
标记数据绑定字段的序列化属性 |
CogSerializationBinderAttribute |
Cognex.VisionPro |
程序集绑定策略属性 |
5.2 常用可序列化对象
| 对象类型 | 说明 | 典型用途 |
|---|---|---|
CogToolBlock |
工具块,可包含多个工具及连线 | 封装完整的检测流程 |
CogToolGroup |
工具组,逻辑集合 | 组织相关工具 |
CogPMAlignTool |
模板匹配工具 | 定位、匹配 |
CogPMAlignPattern |
模板匹配的 Pattern 对象 | 模板保存与复用 |
CogCaliperTool |
卡尺工具 | 边缘检测、宽度测量 |
CogBlobTool |
斑点工具 | 面积、数量统计 |
CogAcqFifoTool |
相机采集工具 | 图像获取 |
CogImageFileTool |
图像文件工具 | 图像读取/保存 |
CogFindLineTool |
找线工具 | 直线检测 |
CogFindCircleTool |
找圆工具 | 圆形检测 |
CogFixtureTool |
定位工具 | 坐标空间变换 |
CogCalibNPointToNPointTool |
N点标定工具 | 相机标定 |
5.3 VisionPro工具与命名空间对照
| 工具名称 | 命名空间 |
|---|---|
CogAcqFifoTool |
Cognex.VisionPro.CogAcqFifoTool |
CogBlobTool |
Cognex.VisionPro.Blob |
CogCaliperTool |
Cognex.VisionPro.Caliper |
CogCNLSearchTool |
Cognex.VisionPro.CNLSearch |
CogImageFileTool |
Cognex.VisionPro.ImageFile |
CogPMAlignTool |
Cognex.VisionPro.PMAlign |
CogSearchMaxTool |
Cognex.VisionPro.SearchMax |
CogToolBlock |
Cognex.VisionPro.ToolBlock |
CogToolGroup |
Cognex.VisionPro.ToolGroup |
CogCalibCheckerboardTool |
Cognex.VisionPro.CalibFix |
CogFixtureTool |
Cognex.VisionPro.CalibFix |
CogColorExtractorTool |
Cognex.VisionPro.ColorExtractor |
CogColorMatchTool |
Cognex.VisionPro.ColorMatch |
CogColorSegmenterTool |
Cognex.VisionPro.ColorSegmenter |
CogFindCircleTool |
Cognex.VisionPro.Caliper |
CogFindLineTool |
Cognex.VisionPro.Caliper |
CogCreateCircleTool |
Cognex.VisionPro.Dimensioning |
CogDistancePointPointTool |
Cognex.VisionPro.Dimensioning |
Cog2DSymbolTool |
Cognex.VisionPro.TwoDSymbol |
CogBarcodeTool |
Cognex.VisionPro.Barcode |
CogOCVTool |
Cognex.VisionPro.OCV |
CogAffineTransformTool |
Cognex.VisionPro.ImageProcessing |
CogHistogramTool |
Cognex.VisionPro.ImageProcessing |
CogImageSharpnessTool |
Cognex.VisionPro.ImageProcessing |
CogSobelEdgeTool |
Cognex.VisionPro.ImageProcessing |
6. CogMisc实用工具方法
CogMisc 是VisionPro提供的静态工具类,包含大量几何计算方法,常与序列化后的对象配合使用:
| 方法 | 签名 | 说明 |
|---|---|---|
AngleLineLine |
static double AngleLineLine(CogLine lineA, CogLine lineB, ICogImage image) |
返回从 LineA 到 LineB 的夹角(弧度) |
AnglePointPoint |
static double AnglePointPoint(double startX, double startY, double endX, double endY) |
返回两点连线的角度(弧度) |
DistancePointLine |
static double DistancePointLine(double x, double y, CogLine line, ICogImage image, out double lineX, out double lineY) |
点到直线的最短距离 |
DistancePointPoint |
static double DistancePointPoint(double startX, double startY, double endX, double endY, out double angle) |
两点之间的距离 |
DistancePointSegment |
static double DistancePointSegment(double x, double y, CogLineSegment segment, ICogImage image, out double segmentX, out double segmentY) |
点到线段的最短距离 |
InsidePointCircle |
static bool InsidePointCircle(double x, double y, CogCircle circle, ICogImage image) |
判断点是否在圆内(可用于求圆度) |
IntersectLineLine |
static bool IntersectLineLine(CogLine lineA, CogLine lineB, ICogImage image, out int numPoints, out double x, out double y, out double angle) |
判断两线是否相交 |
CreateLineParallel |
static CogLine CreateLineParallel(double x, double y, CogLine line, ICogImage image) |
过指定点创建平行线 |
CreateLinePerpendicular |
static CogLine CreateLinePerpendicular(double x, double y, CogLine line, ICogImage image) |
过指定点创建垂线 |
CreateSegmentByAveragingSegments |
static CogLineSegment CreateSegmentByAveragingSegments(CogLineSegment segmentA, CogLineSegment segmentB, ICogImage image) |
通过平均两条线段创建新线段 |
DegToRad |
static double DegToRad(double degrees) |
角度转弧度 |
RadToDeg |
static double RadToDeg(double radians) |
弧度转角度 |
7.坐标空间特殊符号
在VisionPro中使用坐标空间时,以下特殊符号具有特定含义:
| 符号 | 描述 |
|---|---|
@ |
根空间 |
# |
像素空间 |
* |
显示像素空间(仅在为图形指定空间名称时可用) |
^ |
根空间的别名 |
. |
图像的当前选定空间名称(仅可用于 CogImage 对象的方法) |
.. |
当前选定空间的父空间名称 |
$ |
父空间为其子空间创建的子坐标空间(VisionPro 图形系统使用 $ 允许形状的多代层次结构) |
8. 附录
8.1 常用using语句
csharp
using Cognex.VisionPro; // 核心命名空间(CogSerializer 在此)
using Cognex.VisionPro.ToolBlock; // CogToolBlock
using Cognex.VisionPro.ToolGroup; // CogToolGroup
using Cognex.VisionPro.PMAlign; // 模板匹配
using Cognex.VisionPro.Caliper; // 卡尺/找线/找圆
using Cognex.VisionPro.Blob; // 斑点分析
using Cognex.VisionPro.ImageFile; // 图像文件操作
using Cognex.VisionPro.CalibFix; // 标定与定位
using Cognex.VisionPro.Dimensioning; // 几何测量
using Cognex.VisionPro.ImageProcessing; // 图像处理
using Cognex.VisionPro.Barcode; // 条码识别
using Cognex.VisionPro.TwoDSymbol; // 二维码
using System.IO; // Stream 相关
using System.Runtime.Serialization.Formatters.Binary; // BinaryFormatter
8.2 一句话速查
| 需求 | 代码 |
|---|---|
| 保存配置 | CogSerializer.SaveObjectToFile(obj, "path.vpp"); |
| 加载配置 | var obj = CogSerializer.LoadObjectFromFile("path.vpp") as CogToolBlock; |
| 深度复制 | var copy = CogSerializer.DeepCopyObject(source) as CogToolBlock; |
| 完整备份 | CogSerializer.SaveObjectToFile(obj, path, null, CogSerializationOptionsConstants.All); |
| 迁移导出 | CogSerializer.SaveObjectToFile(obj, path, null, CogSerializationOptionsConstants.ExcludeDataBindings); |
| 流式复制 | CogSerializer.SaveObjectToStream(obj, ms); ms.Position = 0; var copy = CogSerializer.LoadObjectFromStream(ms); |