☰
VisionPro二次开发:图片保存与图形标注的完整实现方案
2026/10/2 1:27:27 网站建设 项目流程

做康耐视VisionPro视觉检测项目,图片保存算是最基础的功能,但也是最容易被低估的环节。我刚开始带项目时以为保存一张图片就是对话框加个Bitmap.Save,结果在QuickBuild里右键能存,换成C#二次开发就各种出问题,尤其是要给检测结果图叠加定位框、测量线这些“图形标注”再保存,折腾了一整天才搞清楚CogCompositeImage、CogImageConvertTool、CogImageFileTool这三个对象是怎么配合的。这篇文章把VisionPro图片的打开、保存、以及带图形格式保存的完整方案理一遍,代码都是可以直接抄进自己项目里的,适合正在做VisionPro二次开发、或者被QuickBuild脚本卡住的朋友。

1. 动手之前,先搞懂VisionPro的图像对象体系

1.1 灰度图与彩色图的本质区别

VisionPro里的图像并不是System.Drawing.Bitmap,而是一个CogImage派生对象。最常见的两种是CogImage8Grey和CogImage24PlanarColor。

CogImage8Grey就是8位灰度图,每个像素0到255,工业相机默认输出大多是这种格式,尤其是黑白相机。很多彩色相机在未配置好格式时,采集回来的也可能是灰度图,所以你会发现QuickBuild里显示的界面是黑白的。CogImage8Grey的优点是内存占用小、处理速度快,对定位、灰度检测这些算法非常友好。

CogImage24PlanarColor是24位真彩色图,但它的坑在于“Planar”这个词。它内部不是常见的R、G、B像素交错排列,而是把红色平面、绿色平面、蓝色平面分开存储。这意味着你不能直接把它的像素数据塞给System.Drawing.Bitmap去new,不然颜色会完全乱掉。想要从CogImage24PlanarColor得到普通Bitmap,必须通过CogImageConvertTool转一次,或者调用它的专用接口把三个平面合到一起。

做图片保存前第一步不是写代码,而是先确认你手里拿到的CogImage到底是什么类型。用调试器看一眼Image对象,或者直接打印image.GetType().Name,这一步能省掉后面一大半的排查时间。很多时候现场反馈“保存出来的图是花的”,一查发现是灰度图转彩色图时Conversion参数选错了,根本原因就是没搞清楚源图像格式。

1.2 为什么“保存”前总要通过转换工具

CogImageFileTool虽然能直接保存大多数CogImage派生对象,但遇到CogCompositeImage这种组合对象就不行了。CogCompositeImage是什么呢?你可以把它理解成一个画板,上面叠了一层原始图像,又叠了一层图形标注,比如十字线、检测框、圆弧、文字。它在显示上很好用,但并不是一种标准位图格式,CogImageFileTool不认识它。

所以带图形保存的操作链必然是这样:CogCompositeImage先通过CogImageConvertTool转成CogImage24PlanarColor,再把这个转换结果交给CogImageFileTool写入磁盘。三步缺一不可,顺序也不能乱。

还有一个经验是CogImageConvertTool的Conversion参数,常用CogImageConversionConstants.Color输出彩色图,用Gray输出灰度图。如果你把彩色组合图用Gray转,保存出来画面会变成灰度效果,图形颜色信息直接丢了。这些细节官方文档写得绕,项目里踩一次就记住了。

2. 图片打开与保存的标准姿势:CogImageFileTool

2.1 保存单张图像的完整代码与执行流程

CogImageFileTool是VisionPro专门负责图片读写的工具,在QuickBuild里加一个也能用,但二次开发时代码操作更灵活。保存一张图,标准流程是四步:初始化工具、给图像、打开文件流、执行保存。

using Cognex.VisionPro; using Cognex.VisionPro.ImageFile; CogImageFileTool saveTool = new CogImageFileTool(); saveTool.InputImage = cogImage; // cogImage 是 CogImage 派生对象 // 第二个参数是打开模式,Write表示写入 saveTool.Operator.Open(@"D:\Result\sample.bmp", CogImageFileModeConstants.Write); saveTool.Run(); saveTool.Operator.Close();

注意最后那行Operator.Close()千万别省。Close的作用是释放文件句柄,不调用的话后续对同一个文件做写入或删除时会报“文件被占用”。我见过不少同事在循环里反复保存图片,跑了几百张后突然报错,就是文件句柄没有释放干净。

如果只想保存当前这帧的原始图,不做任何叠加处理,用上面的代码就够了。要特别提醒的是,InputImage必须在Open之前赋值,否则Run的时候工具没有输入图像,保存出来的是一张黑图或者直接报异常。

2.2 保存格式怎么选:bmp、jpg、png、tif

VisionPro判断图片格式不是靠某个参数指定,而是看你Open路径的后缀名。比如写“.bmp”就是BMP格式,写“.png”就是PNG格式。所以你想保存什么格式,直接在路径里控制就行了,不用额外设置属性。

格式压缩方式画质体积适用场景
BMP无压缩无损大调试阶段、需要逐像素还原
PNG无损压缩无损较小检测结果存档、带图形叠加重叠保存
JPG有损压缩有损小报表贴图、远程传输
TIFF可选压缩无损为主大科研级图像、需要保留附加信息

我的建议是:现场检测结果图优先存PNG,因为无损压缩还能把体积控制在比BMP小不少;调试阶段为了省事可以存BMP;只有明确要发报告、贴邮件时才用JPG。JPG的压缩对文字和细线非常不友好,你把检测框和数值标在图上再存成JPG,放大看边缘全是马赛克一样的色块,这就是很多人问“图片保存后失真怎么办”的根源。

2.3 加载已有图片的两种方式

图片加载在二次开发里也很常用,比如离线跑历史图片、重新分析NG样本。用CogImageFileTool读取图片是标准做法,模式和保存类似,只是Open时传Read。

CogImageFileTool loadTool = new CogImageFileTool(); if (File.Exists(imagePath)) { loadTool.Operator.Open(imagePath, CogImageFileModeConstants.Read); loadTool.Run(); CogImage loadedImage = loadTool.OutputImage; loadTool.Operator.Close(); }

这样拿到的loadedImage可以直接往下游工具传,进行定位、测量、检测,和在QuickBuild里拖进来的图片没有本质区别。另一种方式更朴素:直接把图片路径赋值给CogImageFileTool的路径属性,让它在QuickBuild中运行一次。这种方式适合手动测试,不适合程序化批量处理。

还有一个细节,读取的图片如果是JPG,经过压缩后图像细节已经有损失,对高精度测量会有影响。做尺寸回溯分析时建议用BMP或PNG的存档,JPG只适合人眼看个大概。

3. 带图形的保存:把检测结果烙进图片里

3.1 图形从哪来:LastRunRecord与ToolGroup图形记录

带图形保存,意思不是保存成PSD或者SVG那种矢量工程文件,而是把检测工具画出来的十字线、定位框、找圆线圈、文字标签这些图形标注,和原始图像合在一起,再保存成一张普通位图。客户要的结果图、追溯系统里的NG截图,都是这种形态。

VisionPro里工具运行后,每个工具的显示图形都有记录,这些记录存放在ICogRecord里。你可以在QuickBuild界面看到检测框,是因为画面控件的显示层读取了工具的ICogRecord。要在代码里抓取这些图形,最直接的办法是调用ToolGroup的CreateLastRunRecord方法。

ICogRecord rootRecord = mToolGroup.CreateLastRunRecord();

这个rootRecord是一个树形结构,里面有各个工具的图形集合。要注意的是,CreateLastRunRecord必须在ToolGroup运行完一次之后调用,而且最好是在你希望抓取图形的那次运行之后。如果你在Run之前调用,记录里是空的,后面叠加图形自然不会出现在保存结果里。

拿到根记录后,需要遍历它下面所有子记录的Graphics集合。因为工具多了之后记录嵌套层级比较深,我建议写一个递归方法,把所有ICogGraphic对象收集到一个CogGraphicCollection里,再统一交给图像合成器。

3.2 合成并保存:CogCompositeImage加转换工具三步曲代码

带图形保存的完整代码是本文的核心,我直接给完整可用的版本,关键位置有注释:

using Cognex.VisionPro; using Cognex.VisionPro.ImageFile; using Cognex.VisionPro.Operations; // 假设 mToolGroup 是已经运行过的ToolGroup,image是当前帧图像 // 步骤1:把原始图像放进CogCompositeImage CogCompositeImage composite = new CogCompositeImage(); composite.AddImage(image); // 步骤2:从ToolGroup收集图形,加到组合图像上 ICogRecord rootRecord = mToolGroup.CreateLastRunRecord(); CogGraphicCollection graphics = CollectGraphics(rootRecord, new CogGraphicCollection()); composite.AddGraphics(graphics, false); // 步骤3:组合图像不能直接保存,转成24位彩色图 CogImageConvertTool convertTool = new CogImageConvertTool(); convertTool.InputImage = composite; convertTool.Conversion = CogImageConversionConstants.Color; convertTool.Run(); // 步骤4:保存成PNG CogImageFileTool saveTool = new CogImageFileTool(); saveTool.InputImage = convertTool.OutputImage; saveTool.Operator.Open(@"D:\Result\result.png", CogImageFileModeConstants.Write); saveTool.Run(); saveTool.Operator.Close();

递归收集图形的方法:

private CogGraphicCollection CollectGraphics(ICogRecord record, CogGraphicCollection graphics) { if (record == null) { return graphics; } if (record.Graphics != null) { foreach (ICogGraphic graphic in record.Graphics) { graphics.Add((ICogGraphic)graphic); } } if (record.SubRecords != null) { foreach (ICogRecord subRecord in record.SubRecords) { CollectGraphics(subRecord, graphics); } } return graphics; }

几个关键细节:

AddGraphics的第二个参数很关键,传false表示图形坐标跟随图像,传true表示图形固定在显示区域。我们保存检测结果当然要选false,否则图形不会跟着图像的坐标走,保存出来图形位置会错乱。

ConvertTool必须显式指定Conversion为Color。因为CogCompositeImage叠加图形后本质上有RGB信息,不转成彩色输出,后面存图容易得到一张灰度图。

另外我建议保存路径用PNG后缀。图形里的文字、线条这些边缘信息对压缩算法特别敏感,PNG无损压缩能最大程度保真。

3.3 坐标偏了怎么办:图形坐标系换算的坑

很多项目不是单一相机直接定位,尤其做了标定之后,工具的图形坐标可能存放在根坐标系下,而这个坐标系和图像的像素坐标系不是一回事。直接AddGraphics就会出现“图形明明在界面显示是对的,保存出来却偏移甚至消失”的诡异现象。

原因很简单:CogCompositeImage叠加图形时,默认按像素坐标来处理,而标定后的坐标可能是经过变换的物理坐标。处理方法通常是拿到图像坐标空间和输出坐标空间之间的变换矩阵,把图形顶点映射回像素空间再加进去。不同版本的API差异较大,我在这里说一个通用思路:通过image.GetTransform拿到坐标变换,然后遍历图形集合,对每个顶点做映射。如果你的现场图形数据量不大,最稳妥的方案是把处理后的结果图形显示在CogRecordDisplay上,然后用Display自带的保存方法,所见即所得。

// 方式二:利用显示控件自带的保存能力 // 前提是界面上已经用CogRecordDisplay显示了带有图形的结果 cogRecordDisplay.SaveImageAs(@"D:\Result\display_result.bmp", CogImageFileModeConstants.Write);

这种方式的优点是不用自己处理坐标映射,尤其适合多相机标定、坐标系嵌套的情况。缺点是有UI依赖,无人值守的后台程序不好用。如果你做的是带操作界面的上位机,我强烈建议直接走Display保存,省心又不容易出错。

我之前做过一个项目,系统做了九宫格标定,PMAlign工具的图形全部在根坐标系下,直接AddGraphics保存后图形偏了差不多半个画面。后来改成Display保存,问题立刻消失。从那以后,凡是我给客户做上位机,只要界面上有实时画面,我就优先用Display方案;只有纯后台批量处理才用CogCompositeImage方案。

4. 常见问题与排查技巧实录

4.1 常见问题速查表

现象可能原因解决方法
保存出来是黑图InputImage未赋值或图像IsAvailable为false检查输入图像是否有效
保存出来没有检测图形忘记AddGraphics,或CreateLastRunRecord调用时机在Run之前在Run之后获取记录,确认递归收集到图形
图形位置偏移坐标系不一致,图形用了根坐标而图像是像素坐标做坐标映射,或改用CogRecordDisplay保存
JPG图片文字边缘模糊有损压缩导致改用PNG或BMP
循环保存中报文件占用没有调用Operator.Close用try/finally确保Close
中文路径下保存失败VisionPro对中文路径支持欠佳使用纯英文路径

4.2 我踩过的几个坑和解决办法

第一个坑是漏掉Operator.Close。刚开始写批量保存脚本时,我在for循环里不断new CogImageFileTool,但忘记Close,结果程序跑几十张后抛异常。后来我把保存逻辑单独封装成一个方法,用try/finally包裹,在finally里Close,再也没有出现过这个报错。

第二个坑是ToolGroup的CreateLastRunRecord返回空图形。我一开始特别困惑,界面上明明有检测框,代码里却拿不到。后来调试发现,我是在ToolGroup执行Run之前就调了CreateLastRunRecord,当然什么都没有。正确顺序是:先Run,再获取记录,最后合成保存。如果你需要在一次运行结束后自动触发保存,建议把保存逻辑放在脚本的PostRun事件里,或者Job的AfterRun事件里,这时候记录一定已经生成好了。

第三个坑是图形收集不全。递归CollectGraphics时有个小细节,子记录里除了工具图形,可能还包含一些额外的组节点,图形可能挂在多个层级上。最初我只遍历了第一层SubRecords,导致部分图形缺失。改成递归后,完整性和稳定性都上来了。如果你保存的图总是少某些检测框,优先检查递归方法是否足够深,打印一下收集到的图形数量对比界面上实际显示的个数。

第四个坑是保存路径拼接。项目现场经常需要按日期和班次分目录保存,一开始我用的是字符串拼接,结果一天下来目录结构乱七八糟。后来统一用DateTime格式化生成目录和文件名,例如“D:\Result\20250101\080000_123_ok.png”,既保证唯一性,也方便后续追溯。文件名里的时间戳精确到毫秒,基本不会重名。

4.3 关于“图片失真”的进一步说明

很多做上位机的工程师习惯用JPG,因为有现成的照片处理经验。但机器视觉行业里JPG一定要慎用,尤其在带图形保存这条链路上。JPG的压缩算法会对图像做有损编码,检测框边缘的直线会变得模糊,文字数字的边缘会出现伪影,这对人看还好,对后续做OCR或者测量分析就是灾难。

如果你要保存的图片会再次进入检测流程,或者需要做尺寸复核,建议一律用PNG或BMP。如果只是给客户发个报告截图,JPG倒是可以接受。我的做法是保存两份:原始图像用BMP或PNG存档,报表用JPG压缩一份。这样既不浪费磁盘空间,又能保证数据可复现。

4.4 给二次开发项目的封装建议

带图形保存这个功能,我建议所有VisionPro二次开发项目都封装成一个独立工具类,因为十个项目里至少有八个需要这个能力。类里面放几个方法就够用:保存原始图像、保存带图形的图像、加载历史图像。输入参数包括图像对象、ToolGroup引用、保存路径、格式后缀等。

封装的好处很直接,后续维护时只需要改一个地方,不需要满项目搜保存代码。我在好几个项目里复用了同一套封装,每次新项目直接拷贝改路径命名规则就行,稳定性和效率都提升了不少。如果你担心坐标问题,可以在封装里加一个开关,允许调用方指定是用CogCompositeImage还是CogRecordDisplay方案,这样两种场景都能覆盖。

最后分享一个我的个人体会:VisionPro这套东西,很多功能在QuickBuild里点点鼠标就能实现,但一旦跨入二次开发,你必须理解它背后对象之间的关系,而不是靠猜。图片保存这条路,最核心的就是CogImage、CogCompositeImage、CogImageConvertTool、CogImageFileTool这一串链路,理解了这条链,后面再做其他功能,比如报表输出、批次存图、远程检图,都会顺很多。希望这篇整理能帮你少走几个弯路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询