简介:这份资源面向具备一定C#基础、希望进入工业机器视觉领域的开发者,围绕C#与康耐视VisionPro的联合开发展开,可用于视觉检测、图像分析、定位识别及设备通信集成等典型场景的实战参考。压缩包共155个文件,约49.58MB,以34个cs源码、33个dll类库、20个xml配置、11个xlsx数据表及9个resx资源文件为主,另含vpp视觉工具方案、exe可执行程序、sln解决方案与csproj工程文件,构成一套可直接运行的完整工程。目前已有225人学习下载。读者可从中获取C#调用VisionPro的工程组织方式、界面与ROI参数模块的代码结构、视觉工具配置与通信集成思路,适合对照源码理解工业视觉项目从检测到定位识别的落地流程,并作为二次开发与排错的基础模板。
1. 从一堆缓存文件说起:C# 与 VisionPro 联合开发到底在做什么
如果你拿到过一个工业视觉项目的源码包,解压后第一眼看到的不是漂亮的界面截图,而是一堆DesignTimeResolveAssemblyReferences.cache、VisionProSystem.csprojResolveAssemblyReference.cache、VisionProSystem.vshost.exe.config这类文件,别急着关掉。这恰恰说明它是一个在 Visual Studio 里反复编译、现场调试过的真实工程,而不是网上那种跑一遍就丢的 demo。C# 与 VisionPro 联合开发,本质是用 C# 写上位机主程序,把康耐视 VisionPro 的图像采集、工具链运算、结果输出嵌进自己的 WinForm 或 WPF 界面里,让操作员在一个软件里完成取像、定位、测量、判定和通信。它解决的是产线现场“视觉软件和 PLC、MES、运动控制各说各话”的问题,适合做非标自动化、3C 电子、汽车零部件检测的工程师,尤其是那些已经会用 VisionPro 拖工具、但想把流程固化进自己程序的人。
2. 工程结构与引用关系:先看懂 csproj 和那几个 cache 文件
2.1 为什么缓存文件能暴露项目的真实依赖
DesignTimeResolveAssemblyReferences.cache和VisionProSystem.csprojResolveAssemblyReference.cache不是垃圾,它们是 MSBuild 在解析程序集引用时留下的中间产物。前者记录设计器在解析using Cognex.VisionPro;这类命名空间时找到的 DLL 路径,后者记录项目文件里<Reference>节点的解析结果。现场调试过的项目,这两个文件的时间戳往往比源码还新,因为每次改引用、换 VisionPro 版本都会重新生成。看到它们,基本可以判断这个工程至少经历过一次“编译不过→手动加引用→再编译”的循环。
VisionProSystem.csproj.GenerateResource.Cache则和窗体资源有关。WinForm 里如果用了MainForm.resx存图标、字符串或工具参数,这个 cache 会记录资源生成状态。app.config、VisionProSystem.exe.config、VisionProSystem.vshost.exe.config三件套同时出现,说明项目既有运行时配置,也有 Visual Studio 宿主进程的调试配置。常见做法是把 VisionPro 的 license 相关设置、相机 IP、PLC 地址放在app.config的appSettings里,这样现场改参数不用重新编译。
2.2 从 MainForm.Designer.cs 和 ROIParamForm.cs 反推功能划分
MainForm.Designer.cs是主窗体的自动生成代码,里面能看到所有按钮、图像显示控件(通常是CogRecordDisplay)、状态栏的布局。ROIParamForm.cs从名字判断是 ROI 参数设置窗体,现场操作员用它框选检测区域、调阈值、存模板。IOForm.Designer.cs则是 IO 监控或手动控制窗体,用来强制输出、查看输入点状态。这三个文件基本覆盖了“主流程 + 参数配置 + 硬件调试”的典型结构。
如果你要接手或复现这个工程,第一步不是急着 F5,而是打开.csproj看<Reference>里 VisionPro 相关 DLL 的HintPath。常见的是C:\Program Files\Cognex\VisionPro\bin\下的Cognex.VisionPro.dll、Cognex.VisionPro.Core.dll、Cognex.VisionPro.Display.dll等。路径不对,编译就会报“未能找到类型或命名空间”,和热词里那个using jypcie5112;报错是同一类问题。
<!-- VisionProSystem.csproj 片段:引用路径要按现场安装目录改 --> <ItemGroup> <Reference Include="Cognex.VisionPro, Version=9.0.0.0, Culture=neutral, PublicKeyToken=..."> <HintPath>C:\Program Files\Cognex\VisionPro\bin\Cognex.VisionPro.dll</HintPath> <Private>False</Private> </Reference> <Reference Include="Cognex.VisionPro.Core"> <HintPath>C:\Program Files\Cognex\VisionPro\bin\Cognex.VisionPro.Core.dll</HintPath> <Private>False</Private> </Reference> </ItemGroup>Private=False表示不把 DLL 复制到输出目录,因为 VisionPro 是装在系统里的,复制反而容易版本冲突。如果现场机器没装 VisionPro,只拷 exe 是跑不起来的,这一点和纯 C# 小工具完全不同。
2.3 用 app.config 管理现场参数
app.config编译后变成VisionProSystem.exe.config,vshost.exe.config只在 VS 调试时生效。我一般把相机序列号、PLC IP、模板路径、超时时间都放进去,代码里用ConfigurationManager.AppSettings读。这样现场工程师改配置不用装 Visual Studio。
<!-- app.config:现场可改的参数集中放这里 --> <configuration> <appSettings> <add key="CameraIP" value="192.168.1.10"/> <add key="PlcIP" value="192.168.1.20"/> <add key="TemplatePath" value="D:\VisionTemplates\"/> <add key="GrabTimeoutMs" value="3000"/> </appSettings> </configuration>// 读取配置,避免硬编码 string cameraIp = ConfigurationManager.AppSettings["CameraIP"]; int timeout = int.Parse(ConfigurationManager.AppSettings["GrabTimeoutMs"]);参数说明:CameraIP按现场网段改,GrabTimeoutMs太小会误报取像失败,太大又拖节拍,一般 2000 到 5000 之间试。改完app.config要重新生成,或者直接改输出目录里的VisionProSystem.exe.config,后者更快但容易被下次编译覆盖。
3. 从取像到结果输出:C# 调用 VisionPro 工具链的实操路径
3.1 用 CogToolBlock 还是直接调工具
VisionPro 在 C# 里有两种用法:一种是直接new CogFindLineTool()、new CogBlobTool()逐个调用,另一种是先在 VisionPro 里拖好CogToolBlock,存成.vpp,再用CogToolBlock加载。现场项目里ROIParamForm.cs这种参数窗体,通常对应后者,因为操作员需要可视化调 ROI。直接调工具适合逻辑简单、工具数量固定的场景,但一旦要改参数就得改代码。
常见做法是:主流程用CogToolBlock加载.vpp,参数窗体负责修改 Block 里某个工具的Region或RunParams,改完再Save回.vpp。这样 C# 只做“加载、传图、取结果、显示”,算法调整留在 VisionPro 里。
// 加载 ToolBlock 并传入图像 CogToolBlock toolBlock = CogSerializer.LoadObjectFromFile(@"D:\VisionTemplates\Locate.vpp") as CogToolBlock; toolBlock.Inputs["InputImage"].Value = cogImage; // cogImage 来自相机或文件 toolBlock.Run(); double score = (double)toolBlock.Outputs["Score"].Value; double x = ((CogPointMarker)toolBlock.Outputs["Position"].Value).X;逻辑说明:Inputs["InputImage"]的名字必须和 VisionPro 里定义的输入终端一致,大小写敏感。Run()是同步执行,如果工具多、图像大,界面会卡,所以现场常用RunAsync或放到后台线程。Outputs取值前最好判断toolBlock.RunStatus.Result == CogToolResultConstants.Accept,否则可能拿到上一次的旧值。
3.2 图像显示与 ROI 交互
MainForm.Designer.cs里通常有一个CogRecordDisplay,用来显示实时图像和工具结果。把toolBlock的Record赋给display.Record,就能看到 VisionPro 画出的绿线、红框。ROI 参数窗体里,操作员拖动CogRectangleAffine后,要同步更新到toolBlock的输入。
// 把 ToolBlock 的运行记录显示到控件 cogRecordDisplay1.Record = toolBlock.CreateLastRunRecord().SubRecords[0]; cogRecordDisplay1.Fit(true); // 自适应显示 // ROI 窗体里修改区域后回传 CogRectangleAffine rect = new CogRectangleAffine(); rect.SetCenterLengthsRotationScale(centerX, centerY, width, height, angle); toolBlock.Inputs["SearchRegion"].Value = rect;参数说明:Fit(true)保持比例,避免图像拉伸导致操作员误判。SetCenterLengthsRotationScale的参数单位是像素和度,和 VisionPro 界面里显示的一致。改完 ROI 记得toolBlock.Run()一次验证,别等下一张图才发现区域跑偏。
3.3 与 PLC 和上位机的通信边界
热词里出现c#上位机、c# socket bigging receive回调、c#读写注册表,说明现场通信是绕不开的。VisionPro 本身有CogPLC组件,但很多项目还是用 C# 自己写 Socket 或串口。常见做法是:视觉判定完成后,把OK/NG、坐标、角度拼成固定格式字符串发给 PLC;PLC 收到后回一个握手信号,视觉再取下一张。Socket 接收要用BeginReceive回调或Task,别在 UI 线程里Receive阻塞。
// 简单的 Socket 客户端发送结果 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); client.Connect(new IPEndPoint(IPAddress.Parse(plcIp), 5000)); string result = $"{(isOk ? "OK" : "NG")},{x:F3},{y:F3},{angle:F3}\r\n"; byte[] data = Encoding.ASCII.GetBytes(result); client.Send(data);参数说明:5000是 PLC 侧开的端口,按现场改。F3保留三位小数,太多位 PLC 可能解析不了。结尾\r\n是很多 PLC 协议的结束符,缺了会一直等。发送完不要马上Close,现场常用长连接,断了再重连。
3.4 参数持久化与模板管理
ROIParamForm.cs里改完参数,一般要存回.vpp或单独的 XML。直接CogSerializer.SaveObjectToFile会覆盖原模板,现场要留后悔药,所以我会先备份一份带时间戳的。
string templatePath = ConfigurationManager.AppSettings["TemplatePath"]; string backup = Path.Combine(templatePath, $"Locate_{DateTime.Now:yyyyMMddHHmmss}.vpp"); CogSerializer.SaveObjectToFile(toolBlock, backup); // 先备份 CogSerializer.SaveObjectToFile(toolBlock, Path.Combine(templatePath, "Locate.vpp")); // 再覆盖逻辑说明:备份文件多了要定期清理,否则磁盘满会导致保存失败。TemplatePath建议放在非系统盘,避免权限问题。如果现场多人用同一台机器,模板文件要加锁或走版本号,不然 A 改完 B 又覆盖。
4. 避坑与排查:现场调试最容易翻车的五个点
4.1 现象:编译报“未能找到类型或命名空间”,但 DLL 明明在
原因:.csproj里的HintPath指向的是开发机路径,现场机器 VisionPro 装在不同目录,或者版本号对不上。DesignTimeResolveAssemblyReferences.cache里还留着旧路径,VS 有时会优先读缓存。
解决:删掉bin、obj和两个.cache文件,重新打开解决方案,手动改<HintPath>到现场实际路径。如果还不行,检查项目目标框架是不是和 VisionPro 版本匹配,比如 VisionPro 9.0 常用 .NET Framework 4.7.2,别选 .NET 6。
4.2 现象:ToolBlock 加载成功,但Inputs["InputImage"]报 Key 不存在
原因:VisionPro 里输入终端的名字改了,或者.vpp保存时用了中文名。C# 里字符串大小写敏感,空格也算。
解决:在 VisionPro 里打开.vpp,看工具终端的Name属性,复制到代码里。建议统一用英文、无空格命名,比如InputImage、SearchRegion。改完重新保存.vpp,别只改代码。
4.3 现象:取像超时,但相机在 VisionPro 里能正常预览
原因:C# 里用的取像接口和 VisionPro 预览用的不是同一个,或者相机被 VisionPro 占用后没释放。GrabTimeoutMs设得太短也会误报。
解决:确认相机 SDK 的初始化顺序,先Close再Open。如果是 GigE 相机,检查防火墙和网卡巨帧。把GrabTimeoutMs临时调到 10000 看是否还超时,排除节拍问题。
4.4 现象:界面卡死,图像不刷新
原因:toolBlock.Run()在 UI 线程执行,工具多或图像大时阻塞消息循环。CogRecordDisplay刷新也需要 UI 线程。
解决:把Run()放到Task.Run里,结果通过Invoke回 UI 线程更新显示。注意 VisionPro 的CogRecord不能跨线程随便访问,常见做法是在后台线程生成Record,再Invoke赋给display.Record。
4.5 现象:现场改完app.config不生效
原因:改的是项目里的app.config,但运行的是bin\Debug下的VisionProSystem.exe.config,没重新编译就不会同步。vshost.exe.config只在 VS 调试时用,直接双击 exe 不读它。
解决:要么重新生成项目,要么直接改输出目录的VisionProSystem.exe.config。改完重启程序。如果用了 ClickOnce 或安装包,还要检查配置文件是否被打包进去。
5. 进阶技巧:用配置化思路让现场少改代码
5.1 把工具名和输出项做成可配置
现场最怕的是“换个产品就要改代码重新编译”。我一般会在app.config里加一组映射,把 C# 里用的键名和 VisionPro 里的终端名对应起来,这样改产品只改配置。
<appSettings> <add key="ToolBlockPath" value="D:\VisionTemplates\Locate.vpp"/> <add key="InputImageKey" value="InputImage"/> <add key="OutputScoreKey" value="Score"/> <add key="OutputPosKey" value="Position"/> </appSettings>string blockPath = ConfigurationManager.AppSettings["ToolBlockPath"]; string inputKey = ConfigurationManager.AppSettings["InputImageKey"]; string scoreKey = ConfigurationManager.AppSettings["OutputScoreKey"]; CogToolBlock block = CogSerializer.LoadObjectFromFile(blockPath) as CogToolBlock; block.Inputs[inputKey].Value = image; block.Run(); double score = Convert.ToDouble(block.Outputs[scoreKey].Value);这样换一个.vpp只要改ToolBlockPath,终端名一致就不用动代码。参数说明:Convert.ToDouble比直接强转安全,VisionPro 输出可能是float或double。
5.2 用日志记录每次运行的关键数据
现场扯皮最多的是“到底是视觉没判出来还是 PLC 没收到”。我会在每次Run()后写一行 CSV,记录时间、图像路径、分数、坐标、发送结果。不用太复杂,StreamWriter追加就行。
string logLine = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff},{score:F4},{x:F3},{y:F3},{isOk}"; File.AppendAllText(@"D:\VisionLog\run.csv", logLine + Environment.NewLine);注意:多线程写同一文件要加锁,或者用ConcurrentQueue加后台线程落盘。日志目录要定期清理,别把系统盘写满。
5.3 验证方法:用静态图回放代替现场蹲守
新版本上线前,我会把现场采到的典型图(OK、NG、边界)存一个文件夹,写个小循环让程序逐张跑,对比输出和人工标记。这样不用占着产线,也能复现大部分问题。
string[] files = Directory.GetFiles(@"D:\TestImages\", "*.bmp"); foreach (string file in files) { CogImage8Grey img = new CogImage8Grey(new Bitmap(file)); block.Inputs[inputKey].Value = img; block.Run(); double s = Convert.ToDouble(block.Outputs[scoreKey].Value); Console.WriteLine($"{Path.GetFileName(file)} -> {s:F4}"); }参数说明:CogImage8Grey适合黑白相机,彩色图用CogImage24PlanarColor。回放时注意图像位深和现场一致,否则阈值工具结果会偏。
从那以后我每次接 VisionPro 和 C# 联合开发的项目,都强制先跑一遍静态图回放,再上产线联调。这个习惯帮我省掉了至少三次半夜被叫去现场的麻烦。希望帮到你。
本文还有配套的精品资源,点击获取