工业质检方案:相机触发同步、图像预处理加速、缺陷检测模型部署、结果上报

工业质检,说白了就是让机器代替人眼去看产品。我做了这么多年嵌入式,发现很多团队把精力全砸在模型精度上,结果上了产线发现相机触发抖一下、图像传输慢半拍,整个系统就废了。今天咱们就聊聊,怎么在Jetson上把这一整套流程跑通。

1. 相机触发同步:别让图像“迟到”

工业相机和手机相机不一样。产线上产品是流水线过来的,你得在它刚好经过的时候拍。这就涉及到触发同步。

硬件触发 vs 软件触发

我个人习惯用硬件触发。Jetson的GPIO接上相机的触发线,PLC给一个脉冲,相机就拍。延迟通常在微秒级。软件触发呢?走USB或以太网,延迟可能到毫秒级。产线跑得快的时候,差几毫米产品就偏了。

核心要点:硬件触发用GPIO,软件触发用API。产线速度超过0.5m/s时,必须上硬件触发。

多相机同步

有些场景需要多个角度同时拍。比如手机外壳检测,正面、侧面、背面都要看。这时候所有相机得共用一个触发信号。我遇到过一个问题:两个相机虽然同时触发,但曝光时间不同,结果图像时间戳对不上。后来我加了一个硬件帧同步器,所有相机用同一个时钟源,问题就解决了。

小技巧:Jetson的GPIO可以配置为上升沿或下降沿触发。我一般用上升沿,抗干扰能力强一些。

2. 图像预处理加速:别让CPU干苦力

图像预处理,比如去噪、增强、缩放,这些操作在CPU上跑很慢。Jetson有GPU和VIC(视频图像合成器),得用起来。

用VIC做硬件加速

Jetson的VIC模块可以处理色彩空间转换、缩放、旋转。我写了一个pipeline:相机采集的RAW图,直接送到VIC转成RGB,再缩放到模型需要的尺寸。整个过程不经过CPU,延迟从15ms降到了3ms。

// 使用VIC进行图像缩放和色彩转换
#include <nvbuf_utils.h>
#include <cuda.h>

// 创建输入和输出buffer
int input_fd = nv_buffer_create(...);
int output_fd = nv_buffer_create(...);

// 配置VIC转换参数
struct NvBufferTransformParams params;
params.transform_flag = NVBUFFER_TRANSFORM_FILTER;
params.transform_filter = NvBufferTransform_Filter_Smart;
params.src_rect = {0, 0, 1920, 1080};
params.dst_rect = {0, 0, 640, 640};

// 执行转换
NvBufferTransform(input_fd, output_fd, &params);

注意:VIC的输入buffer必须是NV12或YUV420格式。如果相机输出是BGR,得先转格式。我踩过这个坑,折腾了两天才发现。

GPU并行处理

有些预处理操作,比如直方图均衡化、高斯滤波,用CUDA写kernel跑在GPU上,比CPU快几十倍。我一般把预处理分成两步:VIC做格式转换和缩放,GPU做滤波和增强。这样流水线就满了。

3. 缺陷检测模型部署:TensorRT是标配

模型训练好之后,部署到Jetson上必须用TensorRT优化。不优化的话,推理速度可能只有几帧每秒,根本没法用。

模型转换流程

  1. 训练好的模型(比如ONNX格式)导出
  2. 用TensorRT的trtexec工具转成engine文件
  3. 在Jetson上加载engine进行推理
# 将ONNX模型转为TensorRT engine
trtexec --onnx=defect_model.onnx \
        --saveEngine=defect_model.engine \
        --fp16 \
        --workspace=1024 \
        --minShapes=input:1x3x640x640 \
        --optShapes=input:4x3x640x640 \
        --maxShapes=input:8x3x640x640

动态batch

产线上有时候一次来一个产品,有时候来一批。用动态batch可以自适应。我设置min=1, opt=4, max=8。这样单件时延迟低,批量时吞吐高。

经验之谈:FP16精度对缺陷检测来说足够了。我对比过FP32和FP16,准确率只差了0.1%,但速度提升了1.8倍。INT8虽然更快,但需要校准数据集,而且有些模型会掉点严重。

多模型并行

有些场景需要多个模型协同。比如先检测外观缺陷,再检测尺寸偏差。我用了Jetson的Multi-Process Service (MPS),让两个模型同时跑在不同的CUDA stream上,互不干扰。

4. 结果上报:别让数据“烂”在设备里

检测结果得上报到MES系统或者上位机。上报方式有很多种,我推荐用MQTT或者HTTP。

MQTT vs HTTP

特性 MQTT HTTP
实时性 高(推送模式) 中(轮询模式)
带宽占用 低(二进制协议) 高(文本协议)
可靠性 QoS 0/1/2 依赖TCP
适用场景 实时告警、状态上报 批量数据、日志上传

我个人习惯用MQTT上报缺陷告警,用HTTP上报统计数据和日志。这样实时性和可靠性都兼顾了。

# MQTT上报缺陷结果
import paho.mqtt.client as mqtt
import json

client = mqtt.Client()
client.connect("192.168.1.100", 1883, 60)

def report_defect(product_id, defect_type, confidence):
    msg = {
        "product_id": product_id,
        "defect_type": defect_type,
        "confidence": confidence,
        "timestamp": time.time()
    }
    client.publish("factory/defect", json.dumps(msg), qos=1)

避坑指南:我曾经把MQTT的QoS设成0,结果网络抖动丢了几条缺陷数据,产线没及时停机,废了一批产品。后来改成QoS 1,虽然多了一点延迟,但数据一条没丢。

本地缓存

万一网络断了怎么办?我加了一个本地SQLite缓存。上报失败时先存本地,网络恢复后再补报。这样即使断网半小时,数据也不会丢。

整体流程总结

把上面四个环节串起来,就是一套完整的工业质检方案。我画了一张图,方便你理解整个数据流。

工业质检方案数据流 相机触发同步 硬件GPIO触发 多相机同步 图像预处理加速 VIC硬件加速 GPU并行处理 缺陷检测模型 TensorRT推理 动态batch 结果 上报 关键时序要求: • 相机触发到图像采集完成:< 5ms • 图像预处理(VIC+GPU):< 10ms • 模型推理(TensorRT FP16):< 20ms • 结果上报(MQTT QoS 1):< 5ms • 总延迟:< 40ms(满足60fps产线需求) 数据流方向: 相机 → VIC预处理 → GPU增强 → TensorRT推理 → MQTT上报

嗯,这套方案我在三个项目里验证过。一个是手机屏幕检测,一个是PCB焊点检测,还有一个是食品包装检测。效果都还不错,产线节拍能跑到60件/分钟以上。

最后说一句:工业质检不是模型精度越高越好,而是整个系统稳不稳定。我见过太多团队模型精度99.9%,但相机触发抖一下、网络丢个包,实际良率反而下降了。把基础打牢,比什么都重要。


公众号:蓝海资料掘金营,微信deep3321