在自动化质检场景中,传送带速度不断提升,相机帧率虽然够高,但视觉算法如果每帧都跑全图推理,延时往往会突破产线节拍,表现为周期性漏检或整段工件未被判定。解决思路并不复杂:一方面通过ROI(感兴趣区域)提取缩小有效计算面积,另一方面用流水线并行让采集、处理、输出重叠执行,从而把单帧端到端耗时压到安全区间。

ROI提取如何降低单帧计算负担
ROI即感兴趣区域,本质是只截取图像中对检测有用的局部矩形或多边形,丢弃背景。以零件在皮带中央匀速运行为例,镜头视场左右两侧固定是导轨与光照支架,这部分每帧都参与卷积纯粹浪费算力。通过标定相机与机械坐标的映射,可得到工件出现区域的像素坐标,例如x:200,y:80,w:400,h:240,后续推理只送这块子图。
实际落地时ROI不一定静止。如果皮带抖动或相机微偏移,固定框会切到工件边缘。此时可用动态ROI:每帧先跑一次极轻量的背景差分或模板匹配,定位工件包围盒,再以此为ROI送主模型。下面给出OpenCV截取静态ROI的示例,注意特殊字符已转义。
import cv2
# 读取原始帧
frame = cv2.imread('line.jpg')
# 定义ROI矩形:x,y,width,height
roi_rect = (200, 80, 400, 240)
x, y, w, h = roi_rect
# 提取感兴趣区域
roi = frame[y:y+h, x:x+w]
# 仅对roi进行后续检测
result = cv2.Canny(roi, 100, 200)
cv2.imwrite('roi_result.jpg', result)
ROI带来的收益不仅是算力下降,还顺带减少误检。背景里的油污、反光被排除后,模型输入信噪比提高。但要注意ROI过小会漏掉大尺寸偏移的工件,建议预留百分之十余量并配合硬件触发信号做二次确认。
流水线并行的基本结构与线程划分
即便单帧处理降到十五毫秒,若采集、推理、写数据库串行,总延时仍是各阶段之和。流水线并行把过程拆成多个阶段,阶段间用队列连接,前一阶段产出即入队,后一阶段取走处理,大家同时干活。典型划分是:采集线程从相机取帧写入原始队列;预处理线程取帧做ROI截取与归一化;推理线程取ROI送模型;输出线程取结果发PLC或存表。
Python里用threading加queue.Queue即可搭建。队列长度要根据帧率与最慢阶段耗时估算,过短会丢帧,过长会引入延迟堆积。下面代码展示四阶段并行骨架,各阶段独立运行,通过三个队列解耦。
import threading
import queue
import time
raw_q = queue.Queue(maxsize=10)
roi_q = queue.Queue(maxsize=10)
res_q = queue.Queue(maxsize=10)
def capture():
while True:
# 模拟相机取帧
frame = get_frame()
raw_q.put(frame)
def preprocess():
while True:
frame = raw_q.get()
roi = frame[80:320, 200:600]
roi_q.put(roi)
def infer():
while True:
roi = roi_q.get()
out = model_predict(roi)
res_q.put(out)
def output():
while True:
out = res_q.get()
send_to_plc(out)
for t in (capture, preprocess, infer, output):
threading.Thread(target=t, daemon=True).start()
该结构下,若推理是瓶颈且耗时二十毫秒,相机三十帧每秒即每三十三毫秒来一帧,推理线程能轻松消化,原始队列不会满。若模型升级到五十毫秒一帧,则需两路推理线程消费同一队列,或降帧采集。并行不是银弹,必须配合ROI缩减与阶段耗时画像。
参数反推与产线联调避坑
部署前应根据线速度、相机曝光、模型延时反推缓冲深度。假设皮带每秒过五个工件,相机以六十帧每秒拍摄,单帧处理端到端需二十五毫秒,则理论吞吐足够。但实际有抖动,队列深度建议设为峰值耗时除以帧周期的一点五倍,防止突发掉帧。可用日志打印各队列长度观察是否持续满或空。
联调时常犯的错误是把ROI坐标写死却不校准相机安装。振动导致镜头偏移两毫米,几天后ROI切到工件外,漏检率回升。应在开机做自动校准:放标准件触发一次全图检测,刷新ROI。另一个坑是Python的全局锁让CPU密集推理无法真并行,此时要把推理放到独立进程或用C++扩展,线程只做IO与队列搬运。
最后提醒,流水线并行增加了状态追踪难度。某帧在第四阶段报错,要能回溯到原始帧号。建议在队列传递对象中附带frame_id与时间戳,输出线程统一写日志。只有把ROI与并行协同设计,高速产线漏检才能稳定收敛。