工业视觉上位机从 0 到 1(开篇):
一张全景图 + 一条 12 篇的落地路线:从"会用算法",走到"能交付一台视觉设备"
【产线真相】算法识别率 99%,设备三天一台没出货
先说个真事。
去年一个朋友找我救火。他们公司买了一台自动视觉检测设备,算法是一家高校团队做的 Demo——在实验室里,识别率 99%,老板看完当场拍板。
装到产线上,三天,一台产品没正常放行。
我去现场待了半天,发现问题根本不在算法:
- 相机偶尔丢一帧,
nullptr直接把程序打崩,得重启; - 检测结果要发给 PLC,通信线程和界面抢资源,操作员点一下按钮界面就假死十秒;
- 判了 NG,客户要查是哪一批、哪张图,结果系统什么都没存;
- 想调一个阈值,得改代码、重新编译、重新发布,产线停机等半天。
算法没问题。是**"设备软件"这一层,根本没做**。
那一刻我特别理解一件事:会写检测算法的人很多,能把算法变成一台"能在车间跑一个月不出事"的设备软件的人,很少。
而这,正是这个系列要解决的事。
你缺的从来不是算法,是"把算法装进设备里"的那层壳
先给结论——一台工业视觉设备软件,由 8 个模块组成,算法只是其中一个:
工业视觉设备软件(上位机) ┌─────────────────────────────────────────────────────────────┐ │ │ │ ⑥ 交互 UI ⑦ 追溯 ⑧ 部署/稳定性 │ │ ROI/结果/参数 存图/记录/查询 打包/日志/自恢复 │ │ ▲ ▲ ▲ │ │ │ │ │ │ │ ① 采集 ──► ② 处理 ──► ③ 算法 ──► ④ 判定 ──► ⑤ 通信 │ │ 相机取流 去噪/增强 检测(可插拔) Pass/Fail PLC/控制卡 │ │ │ └─────────────────────────────────────────────────────────────┘大多数"机器视觉"简历上写的,是中间的③ 算法。
而真正决定项目能不能上线的,是它在①采集、②处理、④判定、⑤通信、⑥UI、⑦追溯、⑧部署里的表现。
一张表,看清差距
我拿了一份真实的"机器视觉工程师"招聘 JD,把它拆成两边:
| JD 里说的 | 只会算法的人 | 会做设备软件的人 |
|---|---|---|
| “负责视觉方案设计” | 会选模型、调参 | 会算节拍、选相机镜头光源 |
| “对接 PLC / 运动控制” | 没碰过通信 | Modbus-TCP / 串口 / IO 触发 |
| “保证设备稳定运行” | 实验室能跑就行 | 断线重连、异常恢复、跑一个月不崩 |
| “数据可追溯” | 只输出结果 | 存图、存记录、能倒查 |
| “现场调试与交付” | 没到过车间 | 会打包、会排现场故障 |
你如果只会左边那一列,面试官一句"你独立交付过完整设备吗",就聊不下去了。
这个系列,就是帮你把右半边补上。
VisionStation:我们这个系列要亲手做出来的东西
系列里我们从头搭一台工业视觉上位机,我给它起名VisionStation。
它不是玩具,也不是把某个开源框架拆开讲一遍。它是一条完整的、工业上真会遇到的链路:
相机取流 ─► 图像预处理 ─► 可插拔检测算法 ─► Pass/Fail 判定 │ ┌─────────────────────┼─────────────────────┐ ▼ ▼ ▼ 发给 PLC 结果可视化 存图与追溯 (联上设备) (操作员看得懂) (出问题能查)搭完之后,你会有一个能编译、能取流、能联设备、能出结论、能追溯、能打包的最小可用设备软件。它不炫,但它是真的。
12 篇的路线图(单篇也能独立读,但连起来是一条完整的成长线)
| 篇 | 你会拿到什么 |
|---|---|
| 1 | 就是本篇:看懂设备软件长什么样 |
| 2 | 一份能扩展的 Qt + CMake 分层工程骨架 |
| 3 | 稳定拿到工业相机的每一帧 |
| 4 | 一条产线上真用得上的图像预处理链 |
| 5 | 把检测算法做成可插拔插件 |
| 6 | 让上位机联上 PLC / 运动控制卡 |
| 6 | 把算法结果翻译成产线要的 Pass/Fail |
| 7 | 数据与图像可追溯 |
| 8 | 一个操作员敢用的界面(ROI + 结果可视化) |
| 9 | 采集/处理/UI 三线程解耦,跑几小时不卡 |
| 10 | 打包、部署到车间电脑 |
| 11 | 部署与稳定性:在自己电脑能跑,到车间不崩 |
| 12 | 全系列复盘 + 工业视觉开发者的进阶路线 |
(具体顺序以最终发布为准;每篇都能独立看懂,不用回头补前面的。)
【能跑起来的最小实现】一分钟看清全链路
认知的东西说再多,不如看一眼骨架。下面是 VisionStation 主干逻辑的最小骨架——它还不能真跑,但能把"一台设备软件到底在干什么"一次说清:
// 一台视觉设备软件的骨架:一屏看清全链路intmain(intargc,char**argv){QApplicationapp(argc,argv);FrameSource source;// ① 采集:相机 / 离线图Preprocessor prep;// ② 处理:ROI、去噪、增强IDetectPlugin*algo=...;// ③ 算法:可插拔的检测插件Judger judge;// ④ 判定:OK / NG + 分级PlcClient plc;// ⑤ 通信:把结果告诉 PLCMainWindow ui;// ⑥ 交互:给操作员看Tracer tracer;// ⑦ 追溯:存图、存记录QObject::connect(&source,&FrameSource::frameReady,[&](constFrame&f){Frame clean=prep.run(f);// 处理Result result=algo->detect(clean);// 检测Verdict v=judge.decide(result);// 判定plc.send(v);// 通信:通知设备tracer.log(f,result,v);// 追溯:留证据ui.show(f,result);// 交互:给人看});source.start();// 开始取流returnapp.exec();}就这么二十几行,但它就是一台视觉设备软件的心脏。
接下来的 12 篇,我们做的所有事,都是把上面这几个"占位符",一个一个换成真正能在产线上跑的实现:
FrameSource→ 第 3 篇,工业相机采集与帧管理;Preprocessor→ 第 4 篇,产线级图像处理链;IDetectPlugin→ 第 5 篇,把算法做成即插即用的插件;Judger→ 第 7 篇,把算法输出翻译成产线语言;PlcClient→ 第 6 篇,和 PLC / 控制卡稳定通信;Tracer→ 第 8 篇,数据与图像追溯;MainWindow→ 第 9 篇,操作员敢用的界面;- 而让这一切不卡、不崩、能交付的 → 第 2、10、11 篇。
建议你先把这个骨架结构记在脑子里——以后每读一篇,都回来看看它在骨架里的哪个位置。
【能跑起来的最小实现】一个 5 分钟能跑的第一版
如果你手痒,先给一个今晚就能跑起来的最小版本:“读一张图 → 显示它”,这就是 VisionStation 的第一块砖。
// main.cpp —— VisionStation 的最小起点(Qt Widgets)#include<QApplication>#include<QLabel>#include<QPixmap>intmain(intargc,char**argv){QApplicationapp(argc,argv);QLabel view;QPixmappix("test.jpg");// 先用一张本地图代替相机if(pix.isNull()){qWarning("图片没读到,检查路径");return1;}view.setPixmap(pix);view.setWindowTitle("VisionStation v0");view.resize(pix.size());view.show();returnapp.exec();}对应 CMake(第 2 篇会展开,这里先跑通):
# CMakeLists.txt cmake_minimum_required(VERSION 3.16) project(VisionStation LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_AUTOMOC ON) find_package(Qt6 COMPONENTS Widgets REQUIRED) add_executable(visionstation main.cpp) target_link_libraries(visionstation PRIVATE Qt6::Widgets)cmake-Bbuild cmake--buildbuild--configRelease跑起来你会看到一张图。
它离"设备软件"还很远,但它已经站在了起跑线上——下一步,就是把"读一张固定的图"换成"从相机稳定地拿每帧图",把"一个 main 文件"换成"一套分层的工程"。这正是第 2、3 篇的事。
【避坑指南】
坑1:以为"会调 OpenCV"就等于"会做设备软件"
- 现象:算法 Demo 很漂亮,一上产线全崩。
- 原因:设备软件的难点 80% 在算法之外(采集、通信、稳定性、追溯、部署)。
- 正解:把这个系列当"工程课"来读,别只盯算法。
坑2:一上来就去啃成熟框架的源码。
- 现象:打开一个大项目的几十个模块,一脸懵,劝退。
- 原因:你还没有"自己从 0 搭一遍"的直接经验,看什么都是散的。
- 正解:跟着这个系列先搭一个最小闭环,再回头看框架,你会突然看懂它为什么那样设计。
坑3:把"能跑"当成"能交付"。
- 现象:自己电脑上完美,车间电脑双击没反应。
- 原因:部署、依赖、配置、稳定性,是独立的一摊事。
- 正解:从第 2 篇起就有"这是要交付到车间的"意识(外置配置、日志、打包)。
下一篇:先把工程的"地基"打好
下一篇,我们干一件很实在的事:用 Qt + CMake 搭出 VisionStation 的工程骨架——分层、单向依赖、能扩展。
为什么底层不能引用上层、为什么.ui和算法要分家、为什么一个小项目也要认真分层。
在那之前,我想先听你一句:
你现在的项目,是"算法能跑"就结束了,还是"设备能在车间跑一个月"才算完?
你在这两个之间,卡在哪一步?
评论区聊聊,这决定了后面 12 篇我该重点讲哪里。