基于 C# WPF + HALCON 的工业视觉算法工具框架(开源)

一、介绍

1、项目背景

老板: 公司招了个牛马实习生,月薪3000,干软件开发,还得懂计算机算法。

第一天跑去吐槽:"你写的这软件也太难用了,界面卡成PPT,功能一用就崩,你是专门来写Bug的吗?"

实习生: 头也不抬:"别问,3000块自然有3000块的写法。"

老板: "那能不能做一个视觉工具?现场人员点一点就能用那种。"

实习生: "可以,别问原理,问就是封装。"

老板: "什么原理?"

实习生: "说了别问。"

于是,这个基于 WPF + HALCON 的小工具就诞生了。

功能很简单:找线、找圆、读码、模板匹配,就这四板斧。

目标很朴素------让不会写代码的人,也能把视觉检测跑起来。

2、为什么做这个工具

写业务痛点:

  • 现场人员不会写代码
  • 每次换产品都要重新调参数
  • 算法工程师不可能天天站产线旁边
  • 所以需要一个"能点、能拖、能保存、能运行"的视觉配置工具

以前调一个圆,要改代码、编译、运行、截图、发群里问一句"这样行不行"。

现在不一样了,现在可以直接拖 ROI。

效率提高了,头发保住了一点点。

3、项目整体结构

可以放一张项目结构图,介绍几个工程:

  • PiCoreAlgo:核心算法库,封装 HALCON 算法
  • PiCoreAlgoUi / UI:WPF 可视化配置界面
  • PLog:日志模块
  • PNotificationCenter:通知中心,用于 UI 模块通信
  • TestAlg:测试调用工程
  • Dll/halcondotnet.dll:HALCON .NET 依赖

这个界面主要干三件事:

  1. 打开图片

  2. 配置工具

  3. 看结果

老板转头看了看软件功能: "等等,你这日志模块和消息通知怎么写的?我看跑起来还算稳定。"

实习生: "那个啊,PLog 日志模块和 PNotificationCenter 之前章节有讲过。"

老板: "什么章节?"

实习生: "老板,年轻人你渴望力量吗?"

老板: "......什么意思?"

实习生: 从桌子底下抽出一摞书,"可以看看以下的书📕,基本功。

C#运行日志https://blog.csdn.net/qq_54122623/article/details/150564238?spm=1011.2124.3001.6209

C# 观察者模式https://blog.csdn.net/qq_54122623/article/details/160167275?spm=1011.2124.3001.6209

二、UI界面

1、Ui界面介绍

讲 UI,而不是代码。

可以介绍:

  • 左侧/中间:图像显示区
  • 右侧/上方:工具配置区
  • 支持打开图片
  • 支持缩放、拖动
  • 支持添加 ROI
  • 支持运行后显示结果

2、Ui样式

老板兴致上来了: "那界面能不能再好看点?换个皮肤什么的。"

实习生: "好说,我默认写了三种样式,分别是 MyStyles.xamlMyStylesSharp.xamlMyStylesHome.xaml。你想换风格,把 Source="MyStylesHome.xaml" 替换一下就行。"

老板: "这么高级?有什么讲究?"

实习生: "讲究大了。MyStyles 是正常风格,MyStylesSharp 是锐利商务风,MyStylesHome 是居家暖色调------其实就是我把三个按钮颜色换了一下。"

老板: "......就这?"

实习生: "老板,3000块的工资,我能封装出三套皮肤已经是买一送二了。您要是不满意,xaml 文件是开放的,您可以根据个人喜好自己写样式。"

老板: "我自己写?"

实习生: "对,简陋点也无所谓,反正您写出来的大概率比我的还简陋。"

接下来就是

三、找线建模工具

你告诉软件大概在哪找,它负责把边缘抠出来。

老板: "你这视觉软件,找线功能怎么一堆参数?现场工人哪看得懂。"

实习生: "老板别慌,我给你用人话翻译一遍:

  • StartX / StartY------告诉软件从哪开始找。

  • EndX / EndY------告诉软件找到哪为止。两点连条线,就这条线上找边缘,别的地方不管。

  • CaliperNum------放多少个卡尺。相当于派多少个人沿线站岗,人多了查得细,人少了容易漏。

  • LineHeight------往两边找多远。设小了边缘漏了,设大了把隔壁工件的边也抓来了。

  • LineWidth------每个卡尺的宽度,胖卡尺还是瘦卡尺的区别。

  • Threshold------边缘够不够硬。数值越高要求越严,跟找对象一样,眼光太高一个都找不到。"

老板: "那这个 Transition 呢?"

实习生: "方向。黑到白还是白到黑,搞反了边缘就跟你的人生一样,全是错的。"

老板: "......那 Select 呢?"

实习生: "找到一堆边缘选哪个。第一个、最后一个、还是全都要。成年人建议选第一个,别贪。"

老板: "IgnoreEdge 呢?"

实习生: "剔除捣乱的边缘点,防止一颗老鼠屎坏了一锅汤。跟公司开掉摸鱼的一个道理。"

老板: "Sigma 呢?"

实习生: "图太糊了就加点,相当于美颜磨皮,但别加太猛,不然边缘也一起糊没了。"

老板: "那要是调了半天还是找不到呢?"

实习生: "五句话排查法,记好了:

  1. 线没放到边缘附近------你让人家在起点找,边缘在终点,这不扯淡嘛。

  2. Threshold 太高------眼光太高,边缘不配。

  3. Transition 方向反了------南辕北辙。

  4. CaliperNum 太少------就派三个人搜一座山,能找到才怪。

  5. 图像太糊------边缘像被生活磨平了一样,换相机吧,这个3000块真不包。"

老板: "......那这套参数你调好了吗?"

实习生: "默认就能跑。能找、能测、能出结果,3000块的标准已经非常体面了。要自动调参也行------"

老板: "加钱对吧?"

实习生: "老板悟了。"

四、找圆建模工具

老板: "上次找线说完了,这找圆功能又一堆参数,你再给我翻译翻译。"

实习生: "好嘞。找圆的思路很简单------就像一群质检员围着圆站一圈,每个人低头看自己脚下有没有边缘。最后大家把看到的点交上来,系统说:行,我给你们拟合一个圆。"

老板: "那参数呢?"

实习生: "挨个说:

  • CenterX / CenterY------圆心大概在哪。不用很准,大概就行,别指到工件外面去。

  • Radius------大概半径。也就是你告诉软件:圆差不多这么大,别跑太远去找。

  • CaliperNum------安排多少个质检员。人太少,圆拟合不稳;人太多,老板会问你为什么运行慢。3000块的建议16到24个,体面。

  • CaliperLength------每个质检员往内外看多远。太短了边缘在视野外,太长了把隔壁的边也抓来凑热闹。

  • CaliperWidth------卡尺宽度。质检员的眼睛睁多大。

  • Threshold------边缘要多硬才算数。跟招人一样,门槛太高一个合格的都没有。

  • Transition------黑到白还是白到黑。方向反了,质检员全体向后转,找到一个寂寞。

  • Direction------从外往里找,还是从里往外找。你告诉质检员先看哪头。

  • IgnoreEdge------忽略捣乱的边缘点。有人眼神不好报了假点,直接踢出去,防止一颗老鼠屎坏了拟合的圆。

  • Sigma------平滑。图太糊了就加点,跟美颜一个道理,但别太过,不然圆也磨成椭圆了。"

老板: "那要是找不出来呢?"

实习生: "老规矩,五句话排查:

  1. 圆ROI没套准------你圈了个寂寞,圆根本不在里面。

  2. Threshold太高------边缘强度不够,人家不配。

  3. Transition方向反了------质检员全员面壁。

  4. CaliperLength太短------边缘刚好在视野外面,差一毫米就是两个世界。

  5. 图像太糊------边缘像被生活磨平了一样,换相机,这个3000块真不包。"

老板: "总结一下?"

实习生: "找圆失败,一般不是算法摆烂,而是参数没哄好。哄好了,它比狗都听话。"

老板: "那你默认参数哄好了吗?"

实习生: "哄好了。能找、能测、能出结果,3000块的标准,这圆拟合得已经非常体面了。"

五、模板匹配建模工具

老板: "上次找线找圆说完了,这模板匹配又是什么?参数更多了。"

实习生: "模板匹配很好理解------你先给系统看一眼标准样品,然后告诉它:'记住这个东西,下次在图里把它找出来。'"

老板: "就这么简单?"

实习生: "就这么简单。参数我给你翻一遍:

  • ModelIDPath------模板存哪。你得告诉系统把记住的东西放哪个文件夹,路径写错了它就跟失忆了一样,谁都不认识。

  • TrainROIType------训练区域类型。你是圈个矩形还是画个圆让系统认,别选太大,你只是让它记住产品特征,不是让它记住整张图的青春。

  • TrainRow / TrainCol------训练区域中心位置。你告诉系统:盯着这儿看,特征在这。

  • TrainPhi------训练区域角度。产品歪着放的,就告诉它歪了多少度。

  • TrainLength1 / TrainLength2------训练区域宽高。框多大,框大了背景干扰多,框小了特征没圈全。

  • FullImageFlag------是否全图搜索。选是,系统满图找,但慢;选否,只在指定区域找,快。

  • FindROIType------查找区域类型。跟训练一个意思,告诉系统去哪找。

  • FindRow / FindCol------查找区域中心。目标大概在哪,告诉它。

  • FindLength1 / FindLength2------查找区域宽高。范围给够,别目标挪两步就出圈了。

  • MinScore------最低匹配分数。满分100,低于这个分系统就当没看见。设太高,稍微偏一点就装死;设太低,什么阿猫阿狗都认。"

老板: "那后面这几个呢?"

实习生: "ModelingRow / ModelingColumn / ModelingAngle------建模时的位置和角度。就是系统记住模板时产品站哪、朝哪,后续坐标跟随全靠这个基准。"

老板: "那如果目标有点旋转、偏移、缩放,还能认吗?"

实习生: "一般能认。系统没那么矫情,稍微歪点、远点、大点小点,它都能凑合。但如果图片糊得像监控截图,或者你模板区域选得太随意,那就别怪它说------'这谁啊?不认识。'"

老板: "那匹配失败了怎么排查?"

实习生: "还是老规矩:

  1. 训练ROI没选到明显特征------你让人家记了个寂寞。

  2. 查找ROI没覆盖目标位置------目标在框外面,系统看都看不见。

  3. MinScore设置太高------满分100你设99,系统心想:臣妾做不到啊。

  4. 模板区域太大------背景干扰太多,系统不知道该看哪。

  5. 图片亮度变化太大------昨天拍的晴天,今天拍的阴天,系统直接脸盲。

  6. 模型文件路径不对------模板压根没保存成功,系统脑子里是空的。"

老板: "这个第六点怎么加粗了?"

实习生: "因为这是最容易犯的错,仅次于忘记保存Word文档。"

老板: "那你这默认参数都设好了?"

实习生: "设好了。能存、能找、能匹配,3000块的标准,已经认得挺体面了。记住一句话------"

老板: "什么?"

实习生: "你只是让系统记住产品特征,不是让它记住整张图的青春。"

六、读码建模工具

老板: "找线、找圆、模板匹配都说完了,你这还有个读码功能,又是干嘛的?"

实习生: "读码就是识别二维码、DataMatrix这些。产品追溯码、料盘码、工件ID,统统交给它。"

老板: "操作复杂吗?"

实习生: "不复杂,几步走:打开图片,选读码工具,起个名比如code_1,选码类型,然后决定要不要框ROI------要的话拖个矩形把码圈住,设好识别数量和超时时间,点运行,完事。"

老板: "ROI又是什么?"

实习生: "Region of Interest。这个工具有一个朴素原则:能框住就别全图找。"

老板: "全图找不行吗?"

实习生: "不是不行,但就像你在公司群里翻三年前的通知。理论上能找到,实际上你已经开始怀疑人生。所以现场用一定开ROI,只在框里找,速度快还稳。"

老板: "参数呢?"

实习生: "少,就这几个:

  • CodeType------码类型。二维码还是DataMatrix,别选错。选错了就像拿饭卡刷地铁,系统不是不努力,是你俩根本不在一个频道。

  • IsUseRoi------是否启用ROI。建议勾上,理由刚才说了,全图找约等于大海捞针。

  • FindRow / FindCol------ROI中心位置。告诉它大概在哪。

  • FindLength1 / FindLength2------ROI宽高。框大点没事,但一定要把码完整框住,框一半它就不认识了。

  • FindPhi------ROI角度。码歪了就把框也歪一下。

  • ExpectedCount------期望识别几个码。一个就填1,多个就填对应数量。

  • TimeOut------最长识别时间。超过这个时间还没读到就放弃,别让它死磕。

  • DefaultParameters------识别策略。系统预设的读码模式,默认就行,别手贱乱改。"

老板: "那读不出来怎么回事?"

实习生: "常见六大原因:

  1. ROI没框住完整码------码在框外面,系统看都看不见。

  2. 码太小------小到系统怀疑这是不是个码。

  3. 图片反光------一道白光正好打在码上,系统直接瞎了。

  4. 码类型选错了------拿饭卡刷地铁,刷到天荒地老也刷不开。

  5. TimeOut太短------系统刚准备发力,你喊停了。

  6. 码本身印刷质量差------糊了、缺了、脏了,神仙难救。"

老板: "默认能跑吗?"

实习生: "能。打开图,框个ROI,点运行,3000块的标准,已经读得非常体面了。记住一句话:能框住就别全图找,全图找那是跟自己过不去。"

六、总结

老板: "讲了半天,你这几个工具到底能干啥,给我总结一下。"

实习生: "行,一句话总结:FindLineControl负责找线,FindCircleControl负责找圆,FindDataCodeControl负责读码,PatternToolControl负责模板匹配。"

老板: "就这?"

实习生: "就这。说白了,它们解决的不是'算法有多高级'的问题,而是'现场人员能不能点一点就把检测跑起来'的问题。能打开图片,能拖ROI,能调参数,能保存配置,能看检测结果------对于一个月薪3000的牛马实习生来说,已经不能要求更多了。"

老板: "那实际项目里怎么用?总不能天天打开这个配置界面点来点去吧?"

实习生: "老板问到点子上了。实际项目一般不会让用户天天点配置界面。正确的姿势是:先用这个工具把参数调好、保存好,然后在项目代码里调这些配置好的工具。"

老板: "比如?"

实习生: "比如在PiCoreAlgoProject文件夹下面建一个.cs文件,写个项目逻辑类,里面写个ReadQcCode方法专门读二维码。流程大概就是:上位机传图进来,项目类加载配置好的读码工具,调FindDataCode去识别,拿到字符串和结果,返回给上位机。这个配置工具更像是'调参后台',真正上线跑的时候是项目代码在干活。"

老板: "那你这代码结构怎么分的?"

实习生: "三层:

  • PiCoreAlgo------后端算法层,负责集成HALCON,封装找线找圆读码模板匹配这些算法。

  • UI------前端配置层,就是你现在看到的这个界面,加ROI、调参数、保存配置、看结果。

  • TestAlg------测试调用层,模拟上位机调用算法,看看真实项目里怎么把这些工具跑起来。"

老板: "HALCON呢?授权贵不贵?"

实习生: "目前用的学习版。大家都懂。能学习、能测试、能跑Demo,先把流程打通。后续如果继续更新,考虑把底层从HALCON换成OpenCV。"

老板: "OpenCV?"

实习生: "纯免费,部署也轻松。到时候老板再问'这个软件授权多少钱',我就可以自信一点说:老板,这次不要钱。"

老板: "免费的好啊!"

实习生: "免费的通常也意味着更多事情要自己干。这个坑后面再慢慢填。"

老板: "所以下一篇讲什么?"

实习生: "讲这些配置好的工具怎么在真实项目里被调用。怎么在Project目录下创建项目类,怎么写ReadQcCode这样的业务方法,怎么把结果返回给上位机,怎么让视觉工具从'能点点点'变成真正能在产线上跑的检测流程。"

老板: "最后总结一下你这工具?"

实习生: "这个工具不是什么高大上的视觉平台,它只是一个朴素的工业视觉小工具。但它能让现场人员少问几句'这个参数怎么调',也能让开发人员少加几次班。"

老板: "那我可以少招几个人了?"

实习生: "......老板,3000块的牛马只有一个,您看着办。"

老板: "对于3000元的写法来说呢?"

实习生: "这已经是非常有性价比的一集了。 但是可能还是会有BUG"

Giteehttps://gitee.com/Li_zhengyuan/wpf-halcon.git

相关推荐
影寂ldy1 小时前
C#WinForm 窗体基础(入口、部分类、属性、生命周期事件)
开发语言·c#
2301_781833521 小时前
Python 正则表达式入门教程
开发语言·python·正则表达式
gihigo19981 小时前
基于蒙特卡洛的异常值剔除(RANSAC + MC置信区间)—MATLAB实现
开发语言·算法·matlab
Ting.~2 小时前
在java中接入百度地图
java·开发语言·dubbo
小短腿的代码世界2 小时前
Qt对象树析构链与智能指针协同:零泄漏内存管理架构
开发语言·qt·架构
ceclar1232 小时前
C#异步编程async与await
c#·.net
zhaqonianzhu2 小时前
LOL切回桌面问题,采用监控抓出元凶方式
开发语言
Aurorar0rua2 小时前
CS50 x 2024 Notes Arrays - 04
c语言·开发语言·学习方法
一起吃元宵2 小时前
百度网盘下载不限速的办法_百度网盘不限速
开发语言·百度网盘·下载不限速·不限速·百度网盘不限速