尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

VisionPro脚本进阶:巧用代码为复杂数据结构(如二维数组)动态创建输入输出

VisionPro脚本进阶:巧用代码为复杂数据结构(如二维数组)动态创建输入输出 1. 为什么需要动态管理VisionPro的输入输出在工业视觉项目中我们经常遇到一些特殊的数据结构需求。比如检测电路板上的多个焊点时需要用一个二维数组存储每个焊点的坐标和直径或者分析图像中的多个区域时要用嵌套列表保存每个区域的特征值。这些场景下简单的bool、int等基础类型就显得力不从心了。VisionPro的图形化界面确实提供了常见数据类型的快捷添加方式但遇到double[,]这样的二维数组或者自定义的类对象时很多开发者会陷入两难要么费时费力地在层层菜单中寻找隐藏选项要么被迫改用不够优雅的替代方案。我在去年参与的一个半导体检测项目中就深有体会——当时需要同时处理128个检测点的三维坐标如果不用脚本动态创建数组手动操作简直是一场噩梦。2. 动态添加多维数组的完整方案2.1 准备工作与环境配置在开始编写脚本前需要确认几个关键点确保使用的是VisionPro 8.0及以上版本早期版本对动态终端的支持有限在ToolBlock属性中启用Allow Custom Terminals选项建议在非生产环境下先进行测试避免影响现有项目2.2 核心代码实现下面是一个增强版的二维数组创建示例增加了错误处理和初始化逻辑public override bool GroupRun(ref string message, ref CogToolResultConstants result) { try { // 初始化一个3行5列的二维数组 double[,] sensorData new double[3, 5]; // 模拟填充数据实际项目中替换为真实数据 for(int i0; i3; i) { for(int j0; j5; j) { sensorData[i,j] i * 10 j; } } // 检查是否已存在同名终端 if(!mToolBlock.Outputs.Contains(sensorData)) { mToolBlock.Outputs.Add(new CogToolBlockTerminal(sensorData, sensorData)); message 成功创建传感器数据终端; } // 执行工具链 foreach(ICogTool tool in mToolBlock.Tools) { mToolBlock.RunTool(tool, ref message, ref result); } } catch(Exception ex) { message $创建终端失败{ex.Message}; result CogToolResultConstants.Error; } return false; }这段代码改进点包括增加了try-catch异常处理添加了终端存在性检查包含完整的数据初始化过程提供了更有意义的状态消息2.3 实际应用中的注意事项在汽车零部件检测项目中我发现几个容易踩坑的地方内存管理大尺寸数组如1000x1000可能导致内存问题建议分块处理命名规范终端名称避免使用特殊字符最好采用驼峰命名法执行顺序确保在添加终端后再运行依赖该数据的工具调试技巧可以在代码中添加临时日志输出方便排查问题3. 高级应用处理自定义对象3.1 创建自定义类终端除了多维数组我们还可以处理更复杂的自定义类型。比如定义一个包含检测结果的类public class InspectionResult { public string PartID { get; set; } public bool IsDefective { get; set; } public double[] DefectScores { get; set; } public DateTime InspectionTime { get; set; } } // 在脚本中使用 public override bool GroupRun(...) { var result new InspectionResult() { PartID AX-2034, IsDefective false, DefectScores new double[] {0.1, 0.05, 0.02}, InspectionTime DateTime.Now }; mToolBlock.Outputs.Add(new CogToolBlockTerminal(FinalResult, result)); // ...其余代码 }3.2 动态输入的处理技巧动态添加输入终端的方法类似但需要注意数据同步问题。这里分享一个实用技巧public override bool GroupRun(...) { // 从上游工具获取输入 if(mToolBlock.Inputs.Contains(RawData)) { var input (CustomDataType)mToolBlock.Inputs[RawData].Value; // 处理数据... } // 动态添加缺失的输入可选 if(!mToolBlock.Inputs.Contains(ConfigParams)) { mToolBlock.Inputs.Add(new CogToolBlockTerminal(ConfigParams, new ConfigurationParams())); } }4. 终端生命周期管理4.1 安全删除终端的最佳实践原始示例中的删除操作虽然简单但在实际项目中需要更谨慎public void RemoveTerminalSafely(string terminalName) { var terminal mToolBlock.Outputs[terminalName]; if(terminal ! null) { // 先断开所有连接 foreach(var consumer in terminal.GetConsumers()) { terminal.Disconnect(consumer); } // 再移除终端 mToolBlock.Outputs.Remove(terminalName); // 建议强制垃圾回收针对大对象 GC.Collect(); GC.WaitForPendingFinalizers(); } }4.2 终端状态监控方案在长期运行的视觉系统中建议添加终端健康检查public void CheckTerminals() { var report new StringBuilder(); foreach(var input in mToolBlock.Inputs) { report.AppendLine($输入[{input.Name}] 类型:{input.Value?.GetType().Name}); } foreach(var output in mToolBlock.Outputs) { report.AppendLine($输出[{output.Name}] 类型:{output.Value?.GetType().Name}); } File.WriteAllText(TerminalReport.txt, report.ToString()); }5. 性能优化与实战建议在医疗影像处理项目中我们总结出几个性能优化技巧对象复用对于频繁更新的终端复用现有对象而非新建批量操作多个终端更新时使用BeginUpdate/EndUpdate包裹类型优化考虑使用struct代替class减少GC压力异步处理耗时操作放在后台线程避免阻塞主流程一个优化后的示例public override bool GroupRun(...) { mToolBlock.BeginUpdate(); // 开始批量更新 try { // 更新或创建终端1 UpdateTerminal(Data1, GenerateData1()); // 更新或创建终端2 UpdateTerminal(Data2, GenerateData2()); } finally { mToolBlock.EndUpdate(); // 结束批量更新 } } private void UpdateTerminal(string name, object value) { if(mToolBlock.Outputs.Contains(name)) { mToolBlock.Outputs[name].Value value; } else { mToolBlock.Outputs.Add(new CogToolBlockTerminal(name, value)); } }6. 调试与故障排除遇到终端相关问题时的排查步骤检查终端名称拼写大小写敏感验证类型是否匹配使用GetType()打印实际类型查看终端连接状态GetConsumers()方法检查是否有并发访问问题加锁保护共享资源一个实用的调试代码片段public void DebugTerminal(string name) { if(mToolBlock.Outputs.Contains(name)) { var terminal mToolBlock.Outputs[name]; Console.WriteLine($终端[{name}]信息); Console.WriteLine($类型{terminal.Value?.GetType().FullName}); Console.WriteLine($消费者数量{terminal.GetConsumers().Count}); // 对于数组类型打印维度信息 if(terminal.Value is Array array) { Console.WriteLine($数组维度{array.Rank}); for(int i0; iarray.Rank; i) { Console.WriteLine($维度{i}长度{array.GetLength(i)}); } } } }
返回列表