Vision SCL 编程
Vision SCL (Visual Structured Control Language) 是 Vision Studio 的视觉专用编程语言。它在标准 PLC SCL 基础上扩展了视觉数据类型、图像处理函数和推理调用接口,适合实现复杂视觉逻辑。
语言概述
与标准 SCL 的异同
| 特性 | 标准 SCL | Vision SCL |
|---|---|---|
| 基础语法 | IF/FOR/WHILE/CASE | 完全兼容 |
| 数据类型 | BOOL/INT/REAL/STRING/ARRAY | 全部继承 |
| 视觉类型 | 不支持 | Image / Region / Contour / DetectionResult 等 |
| 视觉函数 | 不支持 | 200+ 视觉算子 |
| 推理调用 | 不支持 | ONNX Runtime 推理 |
| 异步执行 | 不支持 | Job 异步提交 + 回调 |
| 编译目标 | PLC VM 字节码 | 视觉中间表示 |
| 运行环境 | PLC 运行时 | Vision Studio 运行时 |
编程模式
Vision SCL 支持两种编程模式:
1. 独立模式:纯 Vision SCL 编写完整视觉程序
PROGRAM VisionProgram
VAR
cam : Camera;
img : Image;
result : DetectionResult;
END_VAR
img := CAM_Capture(cam, TIMEOUT := 5000);
result := OBJ_Detect(img, MODEL := "model.onnx");
VIS_WriteResult(result);
END_PROGRAM
2. 混合模式:卡片图 + Vision SCL 代码片段
在卡片图编辑器中,可以使用 SCL 脚本 卡片嵌入自定义逻辑:
// 在卡片图流程中插入自定义后处理
IF result.confidence > 0.8 THEN
result := result; // 保留高质量检测
ELSE
result.confidence := 0.0; // 过滤低置信度
END_IF;
视觉专用数据类型
Image (图像)
TYPE Image :
STRUCT
width : DWORD; // 图像宽度 (像素)
height : DWORD; // 图像高度 (像素)
channels : BYTE; // 通道数 (1=灰度, 3=BGR, 4=BGRA)
format : ImageFormat; // 像素格式 (enum)
timestamp : LWORD; // 采集时间戳 (TSC)
data_ptr : DWORD; // 图像数据指针 (仅供内部使用)
metadata : STRING[256]; // 元数据 JSON
END_STRUCT
END_TYPE
ImageFormat 枚举:
| 枚举值 | 说明 | 每像素位数 |
|---|---|---|
FORMAT_GRAY8 | 8 位灰度 | 8 bit |
FORMAT_GRAY16 | 16 位灰度 | 16 bit |
FORMAT_BGR24 | 24 位 BGR | 24 bit |
FORMAT_BGRA32 | 32 位 BGRA | 32 bit |
FORMAT_RGB24 | 24 位 RGB | 24 bit |
FORMAT_YUV420 | YUV 420 平面 | 12 bit |
Region (区域)
TYPE Region :
STRUCT
pixel_count : DWORD; // 像素数
bounding_box : Rect; // 外接矩形
centroid_x : REAL; // 质心 X
centroid_y : REAL; // 质心 Y
area : REAL; // 面积 (平方像素)
perimeter : REAL; // 周长 (像素)
// ... 其他矩特征
END_STRUCT
END_TYPE
Contour (轮廓)
TYPE Contour :
STRUCT
point_count : DWORD; // 轮廓点数
length : REAL; // 轮廓长度
is_closed : BOOL; // 是否闭合
center_x : REAL; // 中心 X
center_y : REAL; // 中心 Y
// ... 几何属性
END_STRUCT
END_TYPE
DetectionResult (检测结果)
TYPE DetectionResult :
STRUCT
object_count : DWORD; // 检测目标数
objects : ARRAY[0..255] OF // 目标列表 (最多 256 个)
STRUCT
class_id : WORD; // 类别 ID
class_name : STRING[64]; // 类别名称
confidence : REAL; // 置信度 (0.0~1.0)
x : REAL; // 中心 X
y : REAL; // 中心 Y
width : REAL; // 宽度
height : REAL; // 高度
angle : REAL; // 旋转角度 (度)
END_STRUCT;
inference_time_ms : REAL; // 推理耗时 (毫秒)
status : DWORD; // 状态码
END_STRUCT
END_TYPE
其他数据类型
| 类型 | 说明 | 主要字段 |
|---|---|---|
Rect | 矩形区域 | x, y, width, height |
Circle | 圆 | center_x, center_y, radius |
Line | 直线段 | x1, y1, x2, y2, angle |
Measurement | 测量结果 | value, unit, status, deviation |
DecodeResult | 条码/二维码解码结果 | content, format, confidence |
OCRResult | 文字识别结果 | text, confidence, chars |
MatchResult | 模板匹配结果 | score, x, y, angle |
AnomalyResult | 异常检测结果 | anomaly_score, is_anomaly, heatmap |
ClassifierResult | 分类结果 | class_id, class_name, probabilities |
视觉专用函数
相机控制
| 函数 | 说明 | 语法 |
|---|---|---|
CAM_Open | 打开相机设备 | cam := CAM_Open(device_id) |
CAM_Close | 关闭相机 | CAM_Close(cam) |
CAM_SetParam | 设置相机参数 | CAM_SetParam(cam, param, value) |
CAM_GetParam | 读取相机参数 | value := CAM_GetParam(cam, param) |
CAM_Capture | 采集一帧图像 | img := CAM_Capture(cam, TIMEOUT:=ms) |
CAM_StartStream | 启动连续采集 | CAM_StartStream(cam, callback) |
CAM_StopStream | 停止连续采集 | CAM_StopStream(cam) |
图像处理
| 函数 | 说明 | 语法 |
|---|---|---|
IMG_Read | 从文件加载图像 | img := IMG_Read(path) |
IMG_Save | 保存图像到文件 | IMG_Save(img, path, format) |
IMG_Resize | 缩放图像 | resized := IMG_Resize(img, w, h, mode) |
IMG_CvtColor | 色彩空间转换 | gray := IMG_CvtColor(img, FORMAT_GRAY8) |
IMG_GaussianBlur | 高斯滤波 | blurred := IMG_GaussianBlur(img, ksize, sigma) |
IMG_MedianBlur | 中值滤波 | filtered := IMG_MedianBlur(img, ksize) |
IMG_Canny | Canny 边缘检测 | edges := IMG_Canny(img, low, high) |
IMG_Threshold | 二值化 | binary := IMG_Threshold(img, thresh, maxval, type) |
IMG_ROI | 提取感兴趣区域 | roi := IMG_ROI(img, rect) |
IMG_DrawRect | 绘制矩形 | IMG_DrawRect(img, rect, color, thickness) |
IMG_DrawText | 绘制文字 | IMG_DrawText(img, text, pos, color, scale) |
IMG_MatchTemplate | 模板匹配 | result := IMG_MatchTemplate(img, templ, method) |
目标检测
| 函数 | 说明 | 语法 |
|---|---|---|
OBJ_Detect | 目标检测 | result := OBJ_Detect(img, MODEL:="path") |
OBJ_DetectCustom | 自定义配置推理 | result := OBJ_DetectCustom(img, cfg) |
OBJ_Classify | 图像分类 | result := OBJ_Classify(img, MODEL:="path") |
OBJ_Segment | 语义分割 | mask := OBJ_Segment(img, MODEL:="path") |
OBJ_Anomaly | 异常检测 | result := OBJ_Anomaly(img, MODEL:="path") |
测量
| 函数 | 说明 | 语法 |
|---|---|---|
MEAS_FindCircle | 拟合圆 | circle := MEAS_FindCircle(img, roi) |
MEAS_FindLine | 拟合直线 | line := MEAS_FindLine(img, roi) |
MEAS_DistancePP | 点间距 | dist := MEAS_DistancePP(p1, p2) |
MEAS_DistancePL | 点到线距离 | dist := MEAS_DistancePL(point, line) |
MEAS_Angle | 两线夹角 | angle := MEAS_Angle(line1, line2) |
MEAS_Calibrate | 像素到物理单位 | mm := MEAS_Calibrate(pixels, scale) |
识别
| 函数 | 说明 | 语法 |
|---|---|---|
DEC_Barcode | 条码识别 | result := DEC_Barcode(img, roi) |
DEC_QRCode | QR 码识别 | result := DEC_QRCode(img, roi) |
DEC_DataMatrix | DataMatrix 识别 | result := DEC_DataMatrix(img, roi) |
OCR_Recognize | OCR 文字识别 | result := OCR_Recognize(img, roi, lang) |
结果输出
| 函数 | 说明 | 语法 |
|---|---|---|
VIS_WriteResult | 写结果到 PLC 变量 | VIS_WriteResult(result) |
VIS_WriteVariable | 写指定 PLC 变量 | VIS_WriteVariable(name, value) |
VIS_ReadVariable | 读 PLC 变量 | value := VIS_ReadVariable(name) |
VIS_Log | 写入视觉日志 | VIS_Log(level, message) |
VIS_SaveImage | 保存图像 | VIS_SaveImage(img, path) |
完整示例
产品外观检测
PROGRAM SurfaceInspection
VAR_INPUT
trigger : BOOL;
END_VAR
VAR
cam : Camera;
img : Image;
result : DetectionResult;
defect_count : INT;
pass : BOOL;
END_VAR
// 打开相机
cam := CAM_Open("USB_CAM_1");
// 等待触发
IF trigger THEN
// 采集图像
img := CAM_Capture(cam, TIMEOUT := 3000);
// 预处理
img := IMG_CvtColor(img, FORMAT_GRAY8);
img := IMG_GaussianBlur(img, KSIZE := 5, SIGMA := 1.5);
// 目标检测 (缺陷检测模型)
result := OBJ_Detect(img, MODEL := "surface_defect.onnx");
// 判断结果
defect_count := result.object_count;
pass := (defect_count = 0);
// 输出结果
VIS_WriteVariable("VIS_DEFECT_COUNT", INT_TO_REAL(defect_count));
VIS_WriteVariable("VIS_INSPECT_PASS", BOOL_TO_REAL(pass));
// 有缺陷时保存图像
IF NOT pass THEN
VIS_SaveImage(img, "C:\Darra\HMI\defect_images\");
END_IF;
// 记录日志
VIS_Log(LOG_INFO, "检测完成: " +
(INT_TO_STRING(defect_count)) + " 个缺陷");
END_IF;
CAM_Close(cam);
END_PROGRAM
定位引导
PROGRAM RobotGuiding
VAR_INPUT
part_present : BOOL;
END_VAR
VAR
cam : Camera;
img : Image;
result : MatchResult;
offset_x, offset_y, offset_angle : REAL;
END_VAR
IF part_present THEN
cam := CAM_Open("GIGE_CAM_1");
img := CAM_Capture(cam, TIMEOUT := 2000);
// 模板匹配定位
result := IMG_MatchTemplate(img,
TEMPLATE := "reference_part.png",
METHOD := MATCH_NORMED);
IF result.score > 0.8 THEN
// 计算偏移
offset_x := result.x - 320.0; // 图像中心偏移
offset_y := result.y - 240.0;
offset_angle := result.angle;
// 写偏移量到 PLC (单位: mm)
VIS_WriteVariable("ROBOT_OFFSET_X", offset_x * 0.1);
VIS_WriteVariable("ROBOT_OFFSET_Y", offset_y * 0.1);
VIS_WriteVariable("ROBOT_OFFSET_ANGLE", offset_angle);
VIS_WriteVariable("VIS_JOB_DONE", 1.0);
ELSE
VIS_Log(LOG_WARN, "模板匹配失败, 评分=" +
REAL_TO_STRING(result.score));
VIS_WriteVariable("VIS_JOB_ERROR", 1.0);
END_IF;
CAM_Close(cam);
END_IF;
END_PROGRAM
注意事项
- 异步执行:Vision SCL 程序以 Job 形式异步执行,不会阻塞 PLC 扫描周期
- 内存管理:图像数据占用较大内存,使用后及时释放
IMG_Release(img) - 超时处理:采集和推理操作必须设置超时,防止无限等待
- 模型路径:模型路径支持相对路径(相对于项目目录)和绝对路径
- 错误处理:视觉函数返回值包含状态码,建议检查后再继续