ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

C#上位机与工业相机视觉检测系统全流程实战指南

C#上位机与工业相机视觉检测系统全流程实战指南 在工厂自动化现场摸爬滚打这些年我越来越觉得真正能体现上位机开发功力的不是界面画得多漂亮而是你能不能把一个工业相机稳定地采集、分析、判定、再和PLC握手交互组成一套可落地的视觉检测系统。C#做上位机是绝大多数团队的首选原因是它做界面快、通信库齐全、对接相机SDK也方便网上资料多到数不清。这篇文章我会以自己在实际项目中的做法为主线把从硬件选型、相机连接、图像处理到PLC联动的完整流程拆开讲尤其是那些文档里不会写的踩坑点尽量让刚接触这一块的朋友少走弯路。1. 视觉检测系统的整体思路1.1 你面对的是不是一套“视觉系统”问题很多人一上来就急着选相机、调算法实际上视觉检测项目首先要回答的问题是整套系统到底要完成什么检测动作是判断零件有没有装到位还是测量安装孔的圆心坐标还是读取二维码并把数据传给MES这些需求的不同决定了相机分辨率、镜头焦距、光源方式、触发信号格式都完全不一样。我在需求分析阶段一般会先画一张流程草图上游设备把工件送到检测工位PLC给出到位信号上位机收到信号后触发相机拍照图像处理得到结果再把结果通过IO或网络返回给PLC同时把图片和检测数据存数据库。这张图画完后面所有模块的边界就清晰了。很多人容易忽略的是大部分视觉检测系统最核心的难点不在算法而在“信号什么时候来、结果什么时候走”这件事上。如果连触发源头和结果去向都没定义清楚算法再准也没办法在产线上稳定运行。1.2 为什么用C#而不用别的有同行会问用C直接调Halcon或者VisionPro不是更专业吗我的回答是如果整个系统只是一个单纯的算法demo用任何语言都一样但当你需要一个带界面、带数据库、带MES对接、还要远程维护的系统时C#的性价比就出来了。WinForms或WPF开发速度快System.IO.Ports、System.Net.Sockets、第三方Modbus库一抓一大把SQL Server、MySQL、SQLite都有成熟的驱动和Basler、海康、大华相机的SDK配合也稳定。而且C#的委托和事件机制很适合处理相机回调事件一触发图像就自动到你写好的处理函数里代码结构比C写回调清爽太多。如果你团队里有C底层算法库还可以用P/Invoke或C/CLI封装C#只做界面和调度这也是很多公司“C#原生算法库”混合架构的来源。我实际带项目时还会考虑团队招聘成本一个熟练的C#工程师比一个同时精通C和机器视觉的人好招太多这在中型制造企业里是很现实的问题。1.3 项目的技术栈和模块划分我在大多数视觉检测项目里会把系统拆成几个相对独立的模块设备通信层、图像采集层、图像处理层、业务逻辑层、UI层外加一个公共数据模型层。设备通信层负责和PLC、扫码枪、MES这些外部系统打交道图像采集层封装相机SDK统一向外提供开始采集、停止采集、注册图像回调的接口图像处理层封装OpenCVSharp或直接调用底层算法库业务逻辑层实现状态机决定什么时候拍照、什么时候判定、什么时候对外发信号UI层只做显示和操作不允许直接访问相机和PLC。这样拆的好处是换相机品牌时只需要改采集层换PLC协议时只需要改通信层视觉检测系统的核心逻辑可以原封不动复用。我见过不少项目所有代码揉在一个窗体里十几个Timer和无数个静态变量上线一周后连作者自己都不敢动。模块化虽然前期稍微多写一点接口但后面调试和维护省下的时间远远超出想象。2. 相机选型与连接细节2.1 工业相机选型到底看什么很多新人在选相机时只看像素这是个坑。像素只是其中一个维度真正要一起考虑的是传感器大小、像元尺寸、帧率、接口类型、黑白还是彩色、镜头接口、曝光方式。比如检测一个10mm的工件要求在0.1mm精度内判断尺寸那么至少需要保证视场内一个像素对应的物理尺寸不大于0.05mm也就是我们在选型时常说的像素当量。一个500万像素的相机如果视场设为50mm×40mm水平方向像素数约2448像素当量是50/2448≈0.0204mm足够应付0.1mm的精度检测但如果要检测的是整个A4纸那么大这个像素当量就会变成0.16mm很多细节就看不见了。所以选型前先卡好视场和精度再反过来倒推需要的分辨率而不是直接买最高像素的相机。接口方面GigE适合远距离和多个相机共用一个交换机USB3.0适合短距离和成本敏感的场景Camera Link或CoaXPress一般只有高速高带宽的场合才上。工业现场我更推荐GigE线可以拉几十米而且PoE供电还能少拉一根电源线。还有一个常被忽略的点是黑白还是彩色。纯尺寸测量、位置定位、缺陷检测里黑白相机往往比彩色相机更有优势因为黑白相机没有拜耳阵列插值分辨率利用率更高灰度对比度也更好。只有需要识别颜色差异比如判断线束颜色插错没有才必须上彩色相机。光源方面环形光、条光、背光的选择会影响整个算法复杂度背光能得到清晰轮廓环形光适合表面文字和划痕这个选错后期很难补。2.2 相机SDK接入以Basler为例Basler相机在工业视觉里占有率很高它的pylon SDK有C#示例可以直接在NuGet里找到PylonC.NET包或者用厂商自带的Pylon Viewer生成配置。接入时主要分三步第一步枚举相机获取可用设备列表第二步用相机对象打开设备设置分辨率、曝光时间、增益、触发模式等参数第三步注册图像采集回调启动抓流。为了统一多个相机我习惯封装一个CameraBase类把打开、关闭、参数设置、开始采集、停止采集全部包起来内部再去调用pylon的具体接口界面层永远只面对这个类。代码大致张这样public class CameraBase : IDisposable { private Camera _camera; private ActionImageData _frameHandler; public void Open(string serialNumber) { _camera CameraManager.Open(serialNumber); _camera.Parameters.SetValue(ExposureTime, 3000.0); _camera.Parameters.SetValue(TriggerMode, Off); _camera.ImagesGrabbed OnImageGrabbed; } public void Start(ActionImageData handler) { _frameHandler handler; _camera.StartGrabbing(); } private void OnImageGrabbed(object sender, ImageGrabbedEventArgs e) { var image e.GrabResult; if (image.IsValid) { // 拷贝出来放进队列不能在这里直接跑重算法 _frameHandler?.Invoke(ImageData.FromPylonImage(image)); } } }这里有一个细节要在意pylon的图像回调线程默认可能和UI线程不是同一个如果你直接在回调里更新界面控件WinForms十有八九会崩或卡死必须用委托把图像处理抛回UI线程或者更合理地把图像放到队列里交给独立的处理线程消费。这个线程模型会在下一节展开。2.3 多相机区分与DirectShow的问题很多项目不止一台相机比如同时检测正反两面。如果你用普通的USB摄像头或UVC相机OpenCV下的VideoCapture虽然省事但在多个摄像头之间很容易混淆因为VideoCapture的设备索引不一定是稳定的。我在一个项目里试过同样的索引插拔一次USB之后摄像头A和B就互换了排查了很久才发现是因为USB控制器枚举顺序变了。后来改用DirectShow接口通过设备名字而不是索引来区分摄像头问题就解决了。C#里可以用DirectShow的第三方库或者直接调用MediaFoundation通过过滤器的友好名称匹配你需要的那台设备。工业相机这边反而简单GigE相机有唯一的MAC地址和IPUSB3工业相机也有序列号pylon SDK枚举时就能拿到序列号用序列号建立映射就万无一失。多相机的另一个麻烦是曝光同步。两个相机同时拍同一个产品正反面时如果曝光时刻差了几毫秒可能出现一边拍到工件已经停止、另一边还在运动的情况。这种场景最好用支持硬件同步的相机通过一根同步线把两台相机的触发信号串起来让它们在同一时刻曝光而不是靠上位机分两次触发。2.4 与PLC和MES的通信设计视觉检测系统不是孤立运行的它必须知道工件什么时候到位、完成后要告诉PLC结果是OK还是NG。最常见的实现是三选一离散IO、串口Modbus、以太网TCP。离散IO响应最快、最可靠但需要额外配一块IO卡串口Modbus适合老设备稳定但速度慢以太网TCP最灵活可以同时传状态和结果很多新设备的PLC都支持。如果PLC是西门子还可以直接用C#连接西门子的OPC服务读写DB块省去自己解析报文。我个人的习惯是如果检测节拍要求小于1秒优先走IO硬线因为TCP通信即便只有几毫秒延迟叠加PLC扫描周期后也会让整个流程变得拖沓如果节拍宽裕就全部走TCP/OPC维护成本低。另一个关键点是握手协议不能只发一个OK就不管了必须有握手信号上位机收到“触发请求”后发送“收到触发”PLC收到“收到触发”后清除请求信号上位机检测到请求信号清空后再发送“检测结果”PLC再发“结果已读”双方形成四步握手。没有这套机制生产线上经常会出现误触发或者结果漏读的情况。3. 上位机框架与核心功能模块设计3.1 用委托和事件设计相机回调这里我要详细讲讲委托因为C#的相机SDK回调到处都用得上。有些朋友对委托的理解还停留在“定义一个方法指针”的层面实际在视觉系统里委托更像你给相机“留了个电话”相机每采到一帧画面就拨一次这个电话。具体到代码pylon的回调事件会给你一个IImage对象你在这个事件里要做的不是直接处理图像而是把图像数据拷贝出来塞进一个线程安全的队列。为什么不能直接处理因为相机帧率动辄30fps甚至更高如果在回调里做Canny边缘检测加轮廓筛选毫秒级算法还行算法一复杂就会拖慢采集速度导致丢帧。队列解耦以后采集线程只负责收图算法线程负责分析两者互不拖累。C#里的ConcurrentQueue 或者Channel 都很适合这个场景配合Task或后台线程代码比我自己早年用的List加lock干净得多。下面是一个简单的队列消费模式示意private ChannelImageData _channel Channel.CreateUnboundedImageData(); private CancellationTokenSource _cts new CancellationTokenSource(); private void StartProcessing() { Task.Run(async () { await foreach (var frame in _channel.Reader.ReadAllAsync(_cts.Token)) { var result ProcessImage(frame); UpdateResultOnUi(result); } }); }这种写法最大的好处是采集回调里只需要一行写入队列的代码处理线程不会影响采集帧率。如果后续想并行跑多个算法还可以用多个Task同时读取同一个ChannelC#会自动把每一帧只交给其中一个消费者天然实现了多线程负载均衡。3.2 UI卡顿的根治方案说到UI卡顿这是WinForms上位机被抱怨最多的问题。很多人发现相机一开界面就转圈控件全部假死。原因基本都出在把相机采集和算法处理放在UI线程里了。Windows消息循环要处理鼠标键盘还要一边等SDK回调UI线程一旦被一个耗时的图像处理卡住整个窗口就失去响应。我的做法是三层线程模型UI线程只管显示和用户操作采集线程由相机SDK回调唤醒只做图像拷贝入队处理线程从队列取图跑算法和判定处理完成后把结果数据通过BeginInvoke或异步方法更新到UI。这里要注意处理线程更新UI时不能直接访问控件要用控件的Invoke方法或在异步上下文里调度这一点写多了就会变成肌肉记忆但第一次接触的人很容易忘记然后看到一个奇怪的COMException或者平台调用异常。处理线程更新UI还有一个容易被忽略的性能问题如果处理线程用每秒几十次BeginInvoke去刷新图片框UI消息队列会被塞满鼠标点击都不跟手。我通常在界面刷新上使用定时器比如每秒最多刷新模型视图十次把最新一帧图像复制到显示控件就算完成丢掉中间帧反而更流畅。毕竟人眼也看不出每秒三十帧和每秒十帧的区别但UI响应速度差很多。3.3 图像处理与OpenCVSharp实践图像处理部分我最常用的是OpenCVSharp因为它在NuGet上就能装API跟OpenCV几乎一一对应C#调用起来非常顺手。一个典型的检测流程是原图转灰度高斯滤波去掉噪声二值化分离目标和背景找轮廓然后用轮廓的最小外接矩形或者拟合圆来测量位置和尺寸。有些时候还需要边缘检测算子比如Sobel算子看水平边缘Canny算子提取亚像素级边缘。很多新手会把阈值写死这在实验室测几张图完全没问题一上产线就完蛋因为环境光和产品批次颜色会波动。正确做法是动态阈值可以基于灰度直方图找出双峰之间的谷底或者用OTSU自动计算阈值再配合形态学开操作去掉细小杂点。如果目标背景接近还可以先做差影即用一张没有工件的背景图与当前图做差再把差值中的高亮区域提取出来这个思路在检测异物、缺料、表面瑕疵时尤其好用。我还会刻意把图像处理步骤拆成一个管线每一步都产生中间结果并且允许在界面上勾选显示某一步的结果图。这样调试时能非常直观地看到是灰度变换出了问题还是阈值分割没把目标分离出来而不是只能看到最终NG。很多误检问题打开中间图一眼就能找出原因比埋头改参数快得多。3.4 检测结果的判定与数据存储检测算法输出的不是一张“看着行”的图片而是一组可以量化的结果比如中心坐标、直径、面积、角度、缺陷数量再根据规格上下限判定OK还是NG。这里我强烈建议把所有判定规则做成可配置的不要硬编码在程序里因为现场调试阶段经常会改上下限。可以把检测项、公差、相机编号、产品型号都配置到数据库或XML里换产品时只改配置不用重新编译。数据存储通常用SQLite或SQL Server我自己的项目会根据数据量来选单机设备用SQLite省事多台设备集中管理用SQL Server。这里有个性能细节如果你在每帧图像处理完成后用Insert单条插入节拍一快数据库就会成为瓶颈。应该把结果先缓存到内存列表每隔一段时间或积累一定条数后用SqlBulkCopy批量写入实测可以把写入耗时从几百毫秒压到几十毫秒而且对数据库压力也小得多。批量写入也有风险如果程序在数据还没刷库时崩溃这部分检测记录就丢了。我的妥协方案是同时把关键结果同步写一份本地CSV或日志文件数据库批量写入只是给MES查询用的现场排故以文件为准。这样既保证了性能又不会真正丢失数据。4. 自动化控制流程的打通4.1 触发方式软触发与硬触发视觉检测系统的自动化流程是怎么串起来的关键在于触发方式。软触发就是上位机收到某个指令后主动调相机的软件触发指令相机拍一张图返回给你这种方式适合PLC不需要精确同步的场景比如人工放料后按启动按钮。硬触发则把编码器或传感器的信号直接接到相机光耦输入端由外部硬件信号触发相机曝光上位机只负责接收图像做分析这种方式适合高速产线因为硬触发延时可以做到微秒级不会因为上位机线程调度抖动导致抓拍位置漂移。实际项目里如果产线速度超过每分钟60件我一般会倾向硬触发速度慢或者位置不敏感的软触发加个到位信号就足够。还有一种情况是PLC先给上位机一个软触发请求上位机再用软件触发相机这种模式在现有设备改造中最常见因为不用改接线但你的触发响应时间要控制在几个毫秒内不然就会漏拍。判断触发是否及时除了看代码里的计时最直接的办法是在图像里记录时间戳和触发源。相机SDK一般都能在图像元数据里带上获取时间上位机再叠加当前系统时间两相对比就知道从触发到成像差了多少毫秒。如果偏差波动很大多半是上位机任务调度不稳定需要把触发线程优先级调高或者干脆改为硬触发。4.2 视觉检测的状态机设计把整个检测流程抽象成状态机是让系统稳定不乱的根基。我的状态机一般包括空闲、等待触发、采集中、检测中、等待发送结果、等待结果确认、超时处理。空闲状态下所有模块待命收到触发信号后切换到等待触发确认触发有效后通知相机采集采完图进入检测中算法出结果后进入等待发送结果把结果发给PLC或MES收到对方确认后回到空闲。任何状态都挂一个超时计时器比如等待触发5秒没有来报警提示避免系统因为一个丢掉的信号就永远卡死。用状态机写程序有一个副产品就是你调试的时候可以打印当前状态和切换原因现场一出现问题翻开日志就能看到是卡在等触发还是等确认比靠眼睛盯着相机画面猜高效得多。我记得有一个项目设备总在夜班时莫名停机白班却好好的。纯看现象一点头绪都没有最后查状态机日志发现每天都停在“等待结果确认”这个状态原因是PLC的一个上位机指令被某个报警程序误清了导致握手没有完成。如果没有状态机日志这种偶发问题可能要排查一周。4.3 与西门子PLC等设备的握手协议实例关于和PLC握手我实际项目里很喜欢用一组布尔字做标志位。假设PLC的DB块里定义了两个BoolTrigger和Ack上位机每秒读一次Trigger如果发现Trigger从False变成True说明PLC请求拍照上位机就把Ack置True表示收到PLC看到Ack为True后再把Trigger拉低上位机发现Trigger拉低后把Ack复位一次触发就完整闭环了。这个握手不仅可靠而且不依赖TCP的“发送-接收”顺序天然抗干扰。如果暂时不是西门子用ModbusTCP也一样读线圈Reg1作为Trigger写线圈Reg2作为Ack逻辑完全一样。很多人会忽略一个细节PLC的工艺程序如果扫描周期是10ms握手信号的建立和清除至少要持续20ms以上否则上位机可能会漏读。所以状态机里的循环周期不要设得太短10ms轮询PLC就够了再快反而会制造许多无效报文占用通道带宽。当然握手协议要防止“粘包”和重复触发。上位机必须用边沿检测只有检测到Trigger从0变1的那次才有效电平持续为1不能反复触发。我之前看到一个项目里有人用while循环不断读线圈结果PLC信号还没稳定上位机就触发了三张照片整个流程完全错乱。这种低级错误特别容易出现在没有工业通信经验的新手代码里。4.4 多设备和多相机协同的并发控制项目复杂到一定程度上位机要同时控制两台相机、三台PLC、一台扫码枪并发问题就变得绕不开。C#里有现成的Task、async/await和Channel可以把每个硬件连接包装成一个独立的异步任务。我曾经在一个项目里用Channel实现了图像流水线相机A回调把左视图放入Channel-A相机B回调把右视图放入Channel-B一个合成任务同时取两侧图像校准后拼成完整视野再做检测。两个相机帧率不一致时合成任务会等待慢的那个但因为Channel自带缓冲不会阻塞相机采集实测下来稳定跑了几个班次没有丢帧。这里有一个并发经验不要用Thread.Sleep去做协调它只会让时序变成一团浆糊应该用信号量、Channel、TaskCompletionSource这类的同步原语让代码在等待时主动让出CPU这样系统整体会更可控。多设备协同还有一个容易踩的坑UI上每个设备一个开关但业务逻辑必须允许多设备同时工作。如果有人把PLC通信做成单线程主循环死等一台设备的响应其他设备就会被卡住。正确做法是每个设备一个Task用独立的连接实例通信超时做异步取消这样一个设备出问题只会报警不会拖垮整个系统。5. 常见问题与排查技巧实录5.1 C#调用C算法库遇到AccessViolation C0000005C#调用C的SDK最常见的就是这个异常报错时你会看到类似“尝试读取或写入受保护的内存”或“AccessViolationException”。根源基本都是内存边界不对集中在三种情况结构体布局不一致、缓冲区长度不够、回调函数生命周期没有保持。第一个问题C#的struct默认布局是自动的但C那边往往按指定字节对齐你需要用StructLayoutAttribute和MarshalAs明确声明第二个问题C函数要求你传入byte[]数组并指定长度如果你传入了不足的空间native代码一写入就越界马上就爆这个错。第三个问题最隐蔽C#里如果用一个局部委托传给C做回调委托对象被GC回收后C再回调就访问了无效内存。解决方案是把委托保存成一个静态字段或类字段确保整个程序生命周期内不会被回收。遇到这个异常时先别急着改逻辑用调试器看调用栈如果栈里能看到你调用的native函数名就基本能定位到是参数问题。有一次我排查一个AccessViolation改了三天都没好最后发现是C算法库要求图片数据按4字节对齐而我从相机SDK拿到的Stride并不是整数倍直接把Bitmap像素数组传给native函数就崩了。解决方式是先用Cv2.CopyMakeBorder把图像宽度补成对齐的再传数据一次就通过了。这类问题在机器视觉项目里特别多因为你面对的C库往往不是你写的不知道它对内存布局有多敏感。5.2 相机掉线和数据包丢失的处理GigE相机在工业现场最烦人的是偶尔掉线或者画面突然灰屏。原因百分之七八十出在网卡电源管理和网络包大小。我用Basler相机时系统里禁用网卡的“允许计算机关闭此设备以节约电源”这个选项默认打开相机低负载时网卡休眠就把连接断了断得特别诡异重启软件又能好。另一个常见原因是巨型帧没开或者没设一致GigE Vision的包可以到9000字节如果交换机和网卡配置了一致的巨型帧带宽利用率和稳定性都会好很多。还有就是要锁定相机的IP地址不要把IP设置成DHCP自动获取产线上重启以后分配了一个新IP上位机就找不到相机了。我习惯的做法是把相机和上位机放到一个独立网段专网专用不给它混任何办公网络流量这样基本能杜绝掉线问题。如果做了这些还是偶发掉线我下一步会看网络抓包过滤相机IP后看有没有大量重传包。如果重传包很多说明网线或交换机质量不行或者线太长。工业相机连接用的网线最好选带屏蔽的成品线不要自己压头劣质水晶头在产线振动环境下特别容易接触不良这种问题十分钟出现一次排查起来极其痛苦。5.3 误检率高从图像到算法再到环境视觉检测系统上线初期误检率往往高得让人抓狂很多人第一反应是换算法但真正的问题多半在前端。先看光源反光工件上如果有环境杂光阈值分割出来的区域就会忽大忽小这个必须靠遮光罩或加偏振片解决算法再牛也救不了物理光照。再看相机曝光和增益曝光时间过长会出现运动模糊增益太大会放大噪声二者要结合产线速度重新标定不要沿用实验室参数。最后才是算法本身先看中间结果图把灰度图、阈值图、轮廓图画出来用肉眼确认到底是哪一步把目标弄丢了不要一上来就调Canny的两个阈值。我见过一个项目误检是因为工装上有一颗螺丝反光每次拍照都多出一块亮斑算法把它当成缺陷最后在光源上加了一个遮罩误检直接降到接近于零。所以排查顺序永远是环境、采集、算法、后处理反向排查效率极低。还有一个容易忽略的是产品在夹具里的位置漂移。如果每次都靠一个固定ROI去裁图产品偏了一点特征就出界了。这种情况下要么加定位步骤先找基准点再做后续测量要么把ROI范围放大。很多算法问题不是算法本身不好而是你默认产品每次都停在同一个位置这在自动化设备上根本不现实。5.4 数据库写入慢和UI卡顿的连带问题有人会问SqlBulkCopy听起来好用但缓存结果还没写库软件就关闭了数据不就丢了吗这个问题要分层看如果是单机设备我通常把结果同时写一份本地日志文件日志先落盘数据库批量写只是用来满足MES查询的崩溃后也能从日志恢复。如果是必须实时入库的场合就不要用批量了改用队列加定时flush每100条或每500ms刷一次兼顾实时性和写入性能。UI卡顿的连带问题也有一个坑处理线程频繁BeginInvoke更新控件会导致UI消息队列拥堵界面看起来响应快但实际内部排了一堆没执行的任务。我后来的做法是让UI用一个定时器比如100ms刷新一次结果列表处理线程只把最新结果放到一个共享变量或ConcurrentDictionary里UI定时器去取这样既能看到实时变化又不会因为一帧一刷把界面消息队列塞满。如果你发现界面偶尔闪一下卡顿尤其开机时特别明显还有一个可能性是字体或控件的自动布局在加载大量历史数据时被反复触发。解决办法是处理数据加载时先挂起布局用SuspendLayout和ResumeLayout包住数据填充完再一次性刷新。这类问题虽然不是视觉核心逻辑但现场操作员对卡顿的容忍度很低会直接影响对你整个系统的信任。5.5 现场调试的日志与状态追溯最后想强调日志的重要性。视觉检测系统一旦部署到产线上肉眼很难实时盯着每张图看出问题必须能追溯。我在框架里固定写两类日志一类是系统日志记录状态机切换、通信报文、相机启停、参数改动按天分文件另一类是检测日志记录每条检测的时间、产品ID、结果、关键数值、原图和结果图路径。特别关键的是每次NG都自动保存原始图像这个在做售后分析时是救命稻草。日志文件不要用过于频繁的数据库写入直接写到本地文本文件或按日期命名配合Logger库按级别过滤。现场排故时我一般先看最后一个NG的时间点再翻系统日志看当时状态机卡在哪个环节再看检测日志里图像路径打开原图看是不是光照异常或者夹具没到位整个链路五分钟内就能锁定问题方向。日志里还要记录相机参数快照。很多人排故时不知道当前曝光时间、增益是多少怀疑参数被改过但没法证明。我每次启动软件或产品切换时都会把当前相机参数、光源亮度、算法阈值写进日志和数据库形成一个基线。这样产线维护人员碰过参数、换过光源都能从历史记录里比对出来少吵很多架。带过几个新人之后我发现大家最常犯的错不是技术实现而是把“算法”看得太重把“系统”看得太轻。一套视觉检测系统能稳定跑起来七成功夫在采集和通信三成功夫在算法。相机没调稳触发没握手UI在卡顿再漂亮的Canny边缘检测也落不了地。如果你现在正准备做C#上位机加工业相机的视觉检测项目我建议你从最小的闭环开始相机能出图、PLC能握手、结果能存库先把这条主干打通再去优化算法和界面。这条主干稳了后面遇到的问题基本都是可以逐个解决的工程问题而不是让人丈二和尚摸不着头脑的玄学问题。
返回列表