视觉应用示例
本文档提供 Vision Studio 的五个典型工业视觉应用示例,涵盖外观检测、定位引导、条码识别、尺寸测量和 OCR 字符识别等常见场景。
1. 产品外观检测
场景描述
在注塑件生产线上,对产品表面进行外观缺陷检测,包括划痕、凹陷、缺料、飞边等缺陷类型。检测合格的产品流入下一工序,不合格品自动剔除。
视觉流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 相机采集 │ → │ 预处理 │ → │ 缺陷检测 │ → │ 结果输出 │
│ GigE │ │ 灰度+滤波 │ │ ONNX │ │ 分拣信号 │
│ 2448×2048│ │ 2560×2048│ │ 缺陷模型 │ │ + 图像保存 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
关键配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 相机 | Basler acA2440-75um | GigE, 75fps |
| 触发方式 | 硬件触发 (PLC DO) | 产品到位时触发 |
| 曝光时间 | 3000 µs | 适应白色注塑件 |
| 预处理 | 灰度 + 高斯滤波 (5×5) | 去噪 + 突出特征 |
| 模型 | surface_defect.onnx | YOLOv8m, 640×640 |
| 置信度阈值 | 0.5 | 过滤低质量检测 |
| 检测类别 | 划痕, 凹陷, 缺料, 飞边 | 4 类缺陷 |
| 结果输出 | 分拣 DO + 数据通信 | 分拣 + MES 上报 |
PLC 逻辑 (SCL)
FUNCTION_BLOCK FB_SurfaceInspection
VAR_INPUT
part_present : BOOL; // 产品到位传感器
ejector_ready : BOOL; // 剔除器就绪
END_VAR
VAR_OUTPUT
ejector : BOOL; // 剔除信号
pass_count : INT; // 合格计数
fail_count : INT; // 不合格计数
END_VAR
VAR
trigger_prev : BOOL;
trigger_pulse : BOOL;
fault_type : STRING[32];
END_VAR
// 触发视觉
trigger_pulse := part_present AND NOT trigger_prev;
trigger_prev := part_present;
IF trigger_pulse AND ejector_ready THEN
VIS_JOB_START := TRUE;
END_IF;
// 读取结果
IF VIS_JOB_DONE THEN
VIS_JOB_DONE := FALSE;
IF NOT VIS_JOB_ERROR THEN
IF VIS_RESULT_COUNT > 0 THEN
// 有缺陷,不合格
ejector := TRUE;
fail_count := fail_count + 1;
// 记录缺陷类型
// VIS_RESULT_01_CLASS 包含缺陷类型
ELSE
// 无缺陷,合格
ejector := FALSE;
pass_count := pass_count + 1;
END_IF;
ELSE
// 视觉异常,安全处理
ejector := TRUE;
LOG_ERROR("视觉检测异常");
END_IF;
END_IF;
// 剔除延时复位
IF ejector AND (NOT part_present) THEN
ejector := FALSE;
END_IF;
END_FUNCTION_BLOCK
性能指标
| 指标 | 值 |
|---|---|
| 检测节拍 | 800 ms/件 |
| 检测精度 | 99.2% |
| 误检率 | 0.5% |
| 漏检率 | 0.3% |
| 最大吞吐量 | 75 件/分钟 |
2. 定位引导机器人抓取
场景描述
在无序来料场景中,视觉系统识别工件位置和姿态,引导机器人准确抓取。工件在传送带上随机分布,视觉系统计算每个工件的位置偏移和旋转角度。
视觉流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 相机采集 │ → │ 模板匹配 │ → │ 坐标转换 │ → │ 结果输出 │
│ 俯视安装 │ │ 形状匹配 │ │ 像素→mm │ │ 机器人 │
│ 2448×2048│ │ 参考工件 │ │ 手眼标定 │ │ 抓取坐标 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
手眼标定
视觉系统与机器人之间需要进行手眼标定(Eye-to-Hand 或 Eye-in-Hand),将像素坐标转换为机器人基坐标系下的位置。
标定流程:
- 安装标定板(棋盘格或圆点阵列)
- 机器人带动标定板移动到 9 个不同位置
- 视觉系统记录每个位置的像素坐标
- 记录对应的机器人坐标
- 系统自动计算仿射变换矩阵
关键配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 相机 | Hikvision MV-CA013-UC | USB 3.0, 1280×1024 |
| 镜头 | 12mm 定焦 | 视野 400×300mm |
| 安装方式 | 固定俯视 (Eye-to-Hand) | 相机固定于支架 |
| 匹配方法 | 形状匹配 (ShapeMatch) | 不受光照变化影响 |
| 匹配评分阈值 | 0.7 | 最低匹配评分 |
| 标定精度 | < 0.5 mm | 平均标定误差 |
| 输出坐标 | X, Y, 角度 | 机器人抓取位姿 |
Vision SCL 代码
PROGRAM RobotGuidingProg
VAR
img : Image;
result : MatchResult;
robot_x, robot_y, robot_angle : REAL;
calib_matrix : ARRAY[0..5] OF REAL; // 仿射变换矩阵
END_VAR
// 采集图像
img := CAM_Capture(cam, TIMEOUT := 2000);
// 形状匹配定位
result := IMG_MatchTemplate(img,
TEMPLATE := "workpiece_template.png",
METHOD := MATCH_SHAPE);
// 检查匹配结果
IF result.score > 0.7 THEN
// 像素坐标转机器人坐标 (仿射变换)
robot_x := calib_matrix[0] * result.x +
calib_matrix[1] * result.y + calib_matrix[2];
robot_y := calib_matrix[3] * result.x +
calib_matrix[4] * result.y + calib_matrix[5];
robot_angle := result.angle;
// 输出到机器人
VIS_WriteVariable("ROBOT_TARGET_X", robot_x);
VIS_WriteVariable("ROBOT_TARGET_Y", robot_y);
VIS_WriteVariable("ROBOT_TARGET_ANGLE", robot_angle);
VIS_WriteVariable("ROBOT_GRAB_REQ", 1.0);
ELSE
VIS_Log(LOG_WARN, "定位失败, 评分=" +
REAL_TO_STRING(result.score));
VIS_WriteVariable("ROBOT_GRAB_REQ", 0.0);
END_IF;
END_PROGRAM
性能指标
| 指标 | 值 |
|---|---|
| 定位精度 | ±0.3 mm |
| 角度精度 | ±0.5° |
| 单次定位时间 | 150 ms |
| 抓取成功率 | 99.5% |
3. 条码/二维码读取
场景描述
在物流分拣线上,通过条码或二维码读取包裹上的标识信息,根据信息内容将包裹分拣到不同通道。
视觉流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 相机采集 │ → │ 图像增强 │ → │ 条码识别 │ → │ 分拣输出 │
│ 线阵相机 │ │ 对比度 │ │ Code128 │ │ 通道号 │
│ 4096×1 │ │ 自适应 │ │ QR Code │ │ + 数据库 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
关键配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 相机 | 线阵相机 4096 像素 | 适合高速传送带 |
| 触发方式 | 编码器触发 | 与传送带同步 |
| 图像增强 | 自适应直方图均衡 | 改善条码对比度 |
| 条码类型 | Code128, QR Code, DataMatrix | 自适应识别 |
| 识别超时 | 1000 ms | 快速识别 |
| 分拣输 | 通道号 + 数据库记录 | 实时分拣 + 数据追溯 |
卡片图配置
[编码器触发] ──→ [线阵扫描] ──→ [图像增强] ──→ [条码识别]
│
├──→ [分拣输出]
│ └→ 通道号 DO
│
└──→ [数据库写入]
└→ 追溯记录
结果处理逻辑
// 条码识别后处理
IF decode_result.content <> "" THEN
// 根据条码内容决定分拣通道
CASE decode_result.format OF
FORMAT_CODE128:
// 分拣逻辑
IF LEFT(decode_result.content, 3) = "ORD" THEN
channel := 1; // 订单包裹
ELSIF LEFT(decode_result.content, 3) = "RET" THEN
channel := 2; // 退货包裹
ELSE
channel := 3; // 其他
END_IF;
FORMAT_QRCODE:
channel := 1; // 二维码统一走通道 1
FORMAT_DATAMATRIX:
channel := 4; // DataMatrix 走通道 4
END_CASE;
// 输出分拣信号
VIS_WriteVariable("SORT_CHANNEL", INT_TO_REAL(channel));
VIS_WriteVariable("SORT_TRIGGER", 1.0);
// 记录到数据库
DB_Write("sorting_records",
decode_result.content,
INT_TO_STRING(channel),
NOW());
ELSE
// 未识别,走异常通道
VIS_WriteVariable("SORT_CHANNEL", 0.0);
VIS_Log(LOG_WARN, "条码未识别");
END_IF;
性能指标
| 指标 | 值 |
|---|---|
| 识别率 | 99.7% |
| 识别速度 | < 100 ms/次 |
| 传送带速度 | 2 m/s |
| 最大包裹尺寸 | 600×400×300 mm |
4. 尺寸测量
场景描述
在机加工产线上,对加工完成的零件进行关键尺寸测量,包括孔径、外径、间距、角度等,判断是否在公差范围内。
视觉流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 相机采集 │ → │ 边缘检测 │ → │ 几何测量 │ → │ 结果判断 │
│ 背光照明 │ │ Canny │ │ 圆拟合 │ │ 公差范围 │
│ 500万像素 │ │ 亚像素 │ │ 直线拟合 │ │ OK/NG │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
关键配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 相机 | 5MP 全局快门 | 500 万像素 |
| 镜头 | 远心镜头 | 消除透视误差 |
| 照明 | 背光 LED | 轮廓清晰 |
| 边缘检测 | Canny + 亚像素 | 精度 0.1 pixel |
| 标定 | 标定板 0.05 mm/pixel | 像素当量 |
| 测量项目 | 孔径 3 处, 间距 2 处, 角度 1 处 | 6 个测量项 |
测量结果输出
┌──────────────────────────────────────────────┐
│ 测量报告 │
│ 零件: 支架-A292 │
│ 时间: 2026-07-20 14:30:00 │
│ │
│ ┌──────────┬──────┬──────┬──────┬────────┐ │
│ │ 测量项 │ 标称值 │ 实测值 │ 公差 │ 结果 │ │
│ ├──────────┼──────┼──────┼──────┼────────┤ │
│ │ 孔径 #1 │ 20.0 │ 20.02│ ±0.1 │ OK │ │
│ │ 孔径 #2 │ 12.0 │ 12.03│ ±0.1 │ OK │ │
│ │ 孔径 #3 │ 8.0 │ 8.01 │ ±0.05│ OK │ │
│ │ 间距 #1 │ 50.0 │ 49.98│ ±0.2 │ OK │ │
│ │ 间距 #2 │ 30.0 │ 30.05│ ±0.2 │ OK │ │
│ │ 角度 │ 90.0 │ 89.8 │ ±1.0 │ OK │ │
│ └──────────┴──────┴──────┴──────┴────────┘ │
│ │
│ 总体判定: OK │
└──────────────────────────────────────────────┘
Vision SCL 代码
PROGRAM DimensionMeasurement
VAR
img : Image;
circle1, circle2, circle3 : Circle;
line1, line2 : Line;
dist1, dist2 : REAL;
angle : REAL;
all_ok : BOOL;
BEGIN
// 采集
img := CAM_Capture(cam, TIMEOUT := 3000);
// 边缘检测
img := IMG_Canny(img, LOW := 50, HIGH := 150);
// 测量 3 个孔
circle1 := MEAS_FindCircle(img, ROI := RECT(100, 200, 300, 300));
circle2 := MEAS_FindCircle(img, ROI := RECT(500, 200, 200, 200));
circle3 := MEAS_FindCircle(img, ROI := RECT(300, 500, 200, 200));
// 测量两条边
line1 := MEAS_FindLine(img, ROI := RECT(0, 0, 800, 50));
line2 := MEAS_FindLine(img, ROI := RECT(0, 750, 800, 50));
// 计算间距
dist1 := MEAS_DistancePP(circle1.center_x, circle1.center_y,
circle2.center_x, circle2.center_y);
dist2 := MEAS_DistancePP(circle1.center_x, circle1.center_y,
circle3.center_x, circle3.center_y);
// 计算角度
angle := MEAS_Angle(line1, line2);
// 单位转换 (mm)
circle1.radius := circle1.radius * 0.05;
circle2.radius := circle2.radius * 0.05;
circle3.radius := circle3.radius * 0.05;
dist1 := dist1 * 0.05;
dist2 := dist2 * 0.05;
// 公差判断
all_ok := TRUE;
all_ok := all_ok AND (ABS(circle1.radius - 10.0) < 0.1);
all_ok := all_ok AND (ABS(circle2.radius - 6.0) < 0.1);
all_ok := all_ok AND (ABS(circle3.radius - 4.0) < 0.05);
all_ok := all_ok AND (ABS(dist1 - 50.0) < 0.2);
all_ok := all_ok AND (ABS(dist2 - 30.0) < 0.2);
all_ok := all_ok AND (ABS(angle - 90.0) < 1.0);
// 输出结果
VIS_WriteResult(all_ok);
VIS_WriteVariable("MEAS_OK", BOOL_TO_REAL(all_ok));
END_PROGRAM
性能指标
| 指标 | 值 |
|---|---|
| 测量精度 | ±0.01 mm |
| 重复精度 | ±0.005 mm |
| 单次测量时间 | 500 ms |
| 误判率 | < 0.1% |
5. OCR 字符识别
场景描述
在电子元件生产线上,读取产品表面激光刻印的字符序列号,用于生产追溯和品质管理。字符可能因刻印质量、材料反光等因素导致识别困难。
视觉流程
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ 相机采集 │ → │ 预处理 │ → │ OCR 识别 │ → │ 结果验证 │
│ 高倍放大 │ │ 二值化 │ │ Tesseract │ │ 校验位 │
│ 暗场照明 │ │ 形态学 │ │ 数字+字母 │ │ 格式检查 │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
关键配置
| 参数 | 配置值 | 说明 |
|---|---|---|
| 相机 | 12MP 高分辨率 | 1200 万像素 |
| 镜头 | 50mm 微距 | 高放大倍率 |
| 照明 | 环形暗场 | 突出刻印字符 |
| 预处理 | 二值化 + 形态学闭运算 | 字符区域增强 |
| OCR 引擎 | Tesseract OCR | 工业级 OCR |
| 识别语言 | 英文 + 数字 | 白名单: A-Z, 0-9 |
| 字符格式 | "SN-XXXXXXXX-XX" | 12 位序列号格式 |
| 最低置信度 | 0.8 | 低于此值视为识别失败 |
结果验证逻辑
PROGRAM SerialNumberOCR
VAR
ocr_result : OCRResult;
serial : STRING[32];
valid : BOOL;
checksum : INT;
i : INT;
char_sum : INT;
END_VAR
// 采集与预处理
img := CAM_Capture(cam, TIMEOUT := 3000);
img := IMG_Threshold(img, THRESH := 128, MAXVAL := 255, TYPE := BINARY);
img := IMG_Morphology(img, OP := CLOSE, KSIZE := 3);
// OCR 识别
ocr_result := OCR_Recognize(img,
LANG := "eng",
WHITELIST := "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-");
// 验证结果
valid := FALSE;
IF ocr_result.confidence > 0.8 THEN
serial := ocr_result.text;
// 格式检查: "SN-XXXXXXXX-XX"
IF LEN(serial) = 13 AND
LEFT(serial, 3) = "SN-" AND
MID(serial, 12, 1) = "-" THEN
// 校验位验证 (Luhn 算法)
char_sum := 0;
FOR i := 4 TO 11 DO
char_sum := char_sum + INT_OF_CHAR(MID(serial, i, 1));
END_FOR;
checksum := INT_OF_CHAR(RIGHT(serial, 2));
valid := (char_sum MOD 97 = checksum);
END_IF;
END_IF;
// 输出结果
IF valid THEN
VIS_WriteVariable("PROD_SERIAL", REAL_OF_STRING(serial));
VIS_WriteVariable("PROD_TRACK_OK", 1.0);
// 记录到追溯系统
DB_Write("tracking", serial, NOW());
ELSE
VIS_WriteVariable("PROD_TRACK_OK", 0.0);
VIS_Log(LOG_WARN, "序列号识别失败");
END_IF;
END_PROGRAM
性能指标
| 指标 | 值 |
|---|---|
| 识别率 | 99.3% |
| 误识率 | 0.02% |
| 识别速度 | < 300 ms/次 |
| 最小字符高度 | 15 像素 |
| 适应字符类型 | 点阵、激光、喷码 |