VisionMaster
1. VM能够做什么
2. 采集
3.模板匹配
4. 查找
5. 斑点分析
6. 边缘查找
7. 矩形检测
8. 位置修正(常用)
9. 平行线、四边形查找
10, 角平分线、中线、中垂线、平行线计算、路径提取
11. 图像处理
二次开发
VisionMaster的TCP通信
Group二次开发
Group模块的使用
OK/NG计数方案搭建
畸变校正和畸变校正的使用
VM联合编程
本文档使用 MrDoc 发布
-
+
首页
VM联合编程
# 界面搭建 ## 设置窗口背景色  ## 设置窗口标题  ## 整体界面布局  ## 添加引用  # 功能 ## 选择方案 ```C# /// <summary> /// 当前方案路径 /// </summary> private string currentSolutionPath = String.Empty; /// <summary> /// 方案已加载标志 /// </summary> private bool SolutionIsLoaded = false; private void buttonSelectSolu_Click(object sender, EventArgs e) { try { using (OpenFileDialog ofd = new OpenFileDialog()) { ofd.Filter = "方案文件(*.sol)|*.sol"; if(ofd.ShowDialog() != DialogResult.OK) { currentSolutionPath = string.Empty; } //选择了方案,就会认定当前没有加载方案,等待加载方案按钮按下 SolutionIsLoaded = false; // 保存当前方案路径 currentSolutionPath = ofd.FileName; AppendLog("当前方案路径:" + currentSolutionPath); MessageBox.Show("当前方案路径:" + currentSolutionPath + "\n请点击加载方案按钮以开始加载方案", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information); } } catch (Exception ex) { AppendLog(ex.Message); } } /// <summary> /// 追加日志 /// </summary> /// <param name="message"></param> private void AppendLog(string message) { try { string timeStamp = DateTime.Now.ToString("yy-MM-dd HH:mm:ss-fff"); //如果记录超过1万条,应当清空再添加记录,以防记录的条目巨大引起界面卡顿和闪烁 if (listViewLog.Items.Count > 10000) listViewLog.Items.Clear(); //判断是否是当前界面线程调用此方法 if (listViewLog.InvokeRequired) { listViewLog.BeginInvoke(new Action(() => { listViewLog.Items.Insert(0, new ListViewItem(new string[] { timeStamp, message })); })); } else { listViewLog.Items.Insert(0, new ListViewItem(new string[] { timeStamp, message })); } //如果日志文件夹不存在就创建它 if (!Directory.Exists("./log")) { Directory.CreateDirectory("./log"); } //写入日志到文件 using (FileStream fs = new FileStream("./log/LocateDemoCs.log", FileMode.Append)) { using (StreamWriter sw = new StreamWriter(fs)) { sw.WriteLine(timeStamp + ":" + message); } } } catch (Exception ex) { throw new Exception(ex.Message); } } ``` ## 定时器提醒 ```C# public Form1() { InitializeComponent(); LoadSolutionIndicateTimer.Interval = 300; LoadSolutionIndicateTimer.Tick += LoadSolutionIndicateTimer_Tick; } /// <summary> /// 加载方案按钮闪烁提示,提示选择完了方案接下来就要加载方案 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void LoadSolutionIndicateTimer_Tick(object sender, EventArgs e) { if (!SolutionIsLoaded) { if (buttonLoadSolu.BackColor == Color.DimGray) { buttonLoadSolu.BackColor = Color.Orange; } else { buttonLoadSolu.BackColor = Color.DimGray; } } if (SolutionIsLoaded) { buttonLoadSolu.BackColor = Color.DimGray; } } private void buttonSelectSolu_Click(object sender, EventArgs e) { try { using (OpenFileDialog ofd = new OpenFileDialog()) { ... // 开启定时器 LoadSolutionIndicateTimer.Enabled = true; ... } } catch (Exception ex) { ... } } ``` # 其他 ## 打开项目 ```C# // 打开项目 VmSolution.Load("xxx.sol"); Console.WriteLine(VmSolution.Instance.GetSolutionVersion("xxx.sol", "")); // 获取方案版本号 ``` ## 设置全局变量 ```C# // 设置全局变量 GlobalVariableModuleTool globalVar = (GlobalVariableModuleTool)VmSolution.Instance["全局变量1"]; // 获取全局变量对象 globalVar.SetGlobalVar("失败图片文件名", "失败_" + DateTime.Now.ToString("yyyyMMddHHmmss")); globalVar.SetGlobalVar("成功图片文件名", "成功_" + DateTime.Now.ToString("yyyyMMddHHmmss")); ``` ## 获得各组件的引用 ```C# 注意这里的xxTool直接用是没有的,需要从 VisionMaster4.x.x\Development\V4.x\ComControls\Assembly中引入。 例如:从ImageSourceModuleCs.dll中引入ImageSourceModuleTool 从IMVSBlobFindModu.dll中引入IMVSBlobFindModuTool 从SaveImageCs.dll中引入SaveImageTool // 获得相关工具,以备设置 VmProcedure process = (VmProcedure)VmSolution.Instance["流程1"]; ImageSourceModuleTool input1 = (ImageSourceModuleTool)VmSolution.Instance["流程1.输入1"]; IMVSBlobFindModuTool blob分析 = (IMVSBlobFindModuTool)VmSolution.Instance["流程1.blob分析"]; SaveImageTool output1 = (SaveImageTool)VmSolution.Instance["流程1.blob输出1"]; SaveImageTool output2 = (SaveImageTool)VmSolution.Instance["流程1.blob输出2"]; ``` ## 输入 注意事项 这里踩了很多坑,首先有两种方式,一种是指定路径读图,另一种是从内存中通过byte数组给图 此外,给出通用模块参数设置,防止一些意外 ```C# // ImageSourceModuleTool tool tool.ResetParam(); // 设置SDK取图方式 tool.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.SDK; // 输出Mono8格式,后面的模块要用 tool.ModuParams.OutMono8 = true; // 要开启输出Mono8否则后面的模块可能会出错 ``` ### byte数组输入 ```C# // 打开bmp图片 var bmp = new Bitmap(Pictest2); var bmpBytes = bmpToBytes(bmp); // 这里只是举个例子,具体byte[]怎么来的请各显神通 VmProcedure process = (VmProcedure)VmSolution.Instance["流程1"]; ImageSourceModuleTool input1 = (ImageSourceModuleTool)VmSolution.Instance["流程1.状态1输入"]; // 设置输入1 input1.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.SDK; input1.ModuParams.OutMono8 = true; input1.ModuParams.PixelFormat = ImageSourceParam.PixelFormatEnum.MONO8; input1.SetImageData(new ImageBaseData(bmpBytes, (uint)bmpBytes.Length, bmp.Width, bmp.Height, (int)PixelFormatF.MONO8)); ``` bmpToBytes函数参考(代码来自于网络) ```C# private static byte[] bmpToBytes(Bitmap bmp) { // 获取图像的像素数据 BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, bmp.PixelFormat); // 计算Byte[]数组的大小 int bytesCount = bitmapData.Stride * bitmapData.Height; byte[] bytes = new byte[bytesCount]; // 将像素数据复制到Byte[]数组 Marshal.Copy(bitmapData.Scan0, bytes, 0, bytesCount); // 释放资源 bmp.UnlockBits(bitmapData); // 输出Byte[]数组 return bytes; } ``` ### 指定图像路径输入 就是最后一句改为用SetImagePath函数,(经测试,输入方式要选择LocalImage ```C# VmProcedure process = (VmProcedure)VmSolution.Instance["流程1"]; ImageSourceModuleTool input1 = (ImageSourceModuleTool)VmSolution.Instance["流程1.状态1输入"]; // 设置输入1 input1.ModuParams.ImageSourceType = ImageSourceParam.ImageSourceTypeEnum.LocalImage; input1.ModuParams.OutMono8 = true; input1.ModuParams.PixelFormat = ImageSourceParam.PixelFormatEnum.MONO8; input1.SetImagePath(Pictest2); ``` ## 输出 注意事项 踩了很多坑,建议参考如下代码 ```C# // SaveImageTool tool tool.ResetParam(); // 存图使能,必须开 tool.ModuParams.SaveImageEnable = true; // 不创建目录,否则会出现日期格式的多级目录 tool.ModuParams.GenerateDir = false; // 渲染图缓存数量1,即立刻保存(应该是这个意思吧,没试过 tool.ModuParams.RenderImgCache = 1; // 保存间隔为1,即每一张都保存(应该是这个意思吧,没试过 tool.ModuParams.StorageInterval = 1; // 渲染图输出 tool.ModuParams.RenderImgEnable = true; // 保存格式 SaveImageParam.PixelFormatEnum format tool.ModuParams.PixelFormat = format; // 渲染图输出路径 tool.ModuParams.RenderImgPath = @"xxx\xxx\"; ``` 设置文件名,得通过全局变量间接处理。  # 执行一次 ```C# VmProcedure process = (VmProcedure)VmSolution.Instance["流程1"]; process.Run(); ``` # 获取识别模块的结果 主要是要参考SDK开发手册,从ModuResult中读取 ```C# // 读取Blob数量 blob分析1.ModuResult.BlobNum ``` # 不完整的整体代码 ```C# // 打开项目 VmSolution.Load(sol项目); Console.WriteLine(VmSolution.Instance.GetSolutionVersion(sol项目, "")); // 获取方案版本号 // 打开bmp图片(模拟SDK取图) // 略不重要 // 设置全局变量 GlobalVariableModuleTool globalVar = (GlobalVariableModuleTool)VmSolution.Instance["全局变量1"]; // 获取全局变量对象 globalVar.SetGlobalVar("状态正_失败图片文件名", "状态正失败" + DateTime.Now.ToString("yyyyMMddHHmmss")); globalVar.SetGlobalVar("状态倒_失败图片文件名", "状态倒失败" + DateTime.Now.ToString("yyyyMMddHHmmss")); // 获得相关工具,以备设置 VmProcedure process = (VmProcedure)VmSolution.Instance["流程1"]; ImageSourceModuleTool 全亮input = (ImageSourceModuleTool)VmSolution.Instance["流程1.输入_全亮"]; ImageSourceModuleTool 输入类型1 = (ImageSourceModuleTool)VmSolution.Instance["流程1.输入1"]; ImageSourceModuleTool 输入类型2 = (ImageSourceModuleTool)VmSolution.Instance["流程1.输入2"]; IMVSBlobFindModuTool blob分析1 = (IMVSBlobFindModuTool)VmSolution.Instance["流程1.blob分析1"]; IMVSBlobFindModuTool blob分析2 = (IMVSBlobFindModuTool)VmSolution.Instance["流程1.blob分析2"]; SaveImageTool output1 = (SaveImageTool)VmSolution.Instance["流程1.blob输出1"]; SaveImageTool output2 = (SaveImageTool)VmSolution.Instance["流程1.blob输出2"]; // 设置输入 // 请参考上面的输入要点 // 设置输出 // 请参考上面的输出要点 // 运行 process.Run(); // 打印结果 Console.WriteLine("状态1" + blob分析1.ModuResult.BlobNum); Console.WriteLine("状态2" + blob分析2.ModuResult.BlobNum); Console.WriteLine(process.Name + "success"); ```
张泽楠
2025年12月31日 16:30
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
分享
链接
类型
密码
更新密码