当前位置: 首页 > news >正文

高通跃龙QCS9100平台上工业缺陷检测实战(1): 从摄像头到端侧推理的最小闭环

💡 前言

本系列将聚焦高通跃龙QCS9100平台实施工业缺陷检测。
本文第一篇我们在该QCS9100平台将缺陷检测链路完整跑通

你跑完这篇,应该能看到两件非常具体的东西:

  • runs/里不断冒出带框的图片
  • 终端里能看到每次推理大概多少毫秒、FPS 大概多少

本文先使用ONNXRuntime(CPU)完成闭环,目的是优先把“摄像头/预处理/后处理/可视化输出”链路固定下来;在此基础上,第二篇再切换到 QNN/HTP。

1. 运行结果

  • 输入:USB 摄像头(一般是/dev/video0),也可以换成本地图片/视频先自测
  • 输出
    • runs/下持续生成带框图片
    • 控制台持续打印:推理耗时(ms)和 FPS(滑动窗口)

2. 环境准备

2.1 硬件

  • Thundercomm的基于高通跃龙QCS9100 平台 Linux OS的AI边缘盒子
  • USB UVC 摄像头(最省事;MIPI 相机后续工程化再展开)

2.2 软件

  • Python 3.10
  • GStreamer(用于验证相机与定位问题)
  • Python 包:numpyopencv-python-headlessonnxruntime

查看基础信息(确认工具与版本):

uname-apython3-Vgst-launch-1.0--version

3. 摄像头验证

确认摄像头节点:

ls-l/dev/video*

无显示环境也能验证(只看 fps):

gst-launch-1.0 v4l2srcdevice=/dev/video0!videoconvert!fpsdisplaysink video-sink=fakesink text-overlay=falsesync=false-v

如果这一步不稳定(掉帧/卡住/打不开),请先排查驱动/权限/像素格式问题,再继续后续推理步骤(本文第 7 节提供了排查清单)。

4. 安装依赖

(Ubuntu/Debian 类系统示例)

sudoaptupdatesudoaptinstall-ypython3-pip python3-venvmkdir-p~/defect_demo&&cd~/defect_demo python3-mvenv venvsourcevenv/bin/activate pipinstall-Upip pipinstallnumpy opencv-python-headless onnxruntime

5. 模型准备

你最终肯定会用自训练的缺陷模型。但在这一步,先用通用检测模型(比如YOLO)把流程跑通:流程没跑通前,模型对不对根本无从谈起。

在 PC 上导出 ONNX(示例):

pipinstallultralytics yoloexportmodel=yolov8n.ptformat=onnximgsz=640opset=12

得到yolov8n.onnx后,拷贝到设备端:

mkdir-p~/defect_demo/modelsscpyolov8n.onnx<user>@<device-ip>:/home/<user>/defect_demo/models/

提示:若你已自训练缺陷模型,直接把文件命名为models/defect.onnx,下文也同样适用。

6. 推理与可视化

在设备端创建infer_cam_onnx.py(可直接复制粘贴运行):

importosimporttimefrompathlibimportPathimportcv2importnumpyasnpimportonnxruntimeasort MODEL_PATH="models/yolov8n.onnx"# 换成你的缺陷模型也可以DEVICE="/dev/video0"IMG_SIZE=640CONF_THRES=0.25IOU_THRES=0.45SAVE_DIR=Path("runs")SAVE_DIR.mkdir(parents=True,exist_ok=True)defletterbox(im,new_shape=640,color=(114,114,114)):h,w=im.shape[:2]ifisinstance(new_shape,int):new_shape=(new_shape,new_shape)r=min(new_shape[0]/h,new_shape[1]/w)nh,nw=int(round(h*r)),int(round(w*r))im_resized=cv2.resize(im,(nw,nh),interpolation=cv2.INTER_LINEAR)top=(new_shape[0]-nh)//2bottom=new_shape[0]-nh-top left=(new_shape[1]-nw)//2right=new_shape[1]-nw-left im_padded=cv2.copyMakeBorder(im_resized,top,bottom,left,right,cv2.BORDER_CONSTANT,value=color)returnim_padded,r,(left,top)defxywh2xyxy(x):y=x.copy()y[...,0]=x[...,0]-x[...,2]/2y[...,1]=x[...,1]-x[...,3]/2y[...,2]=x[...,0]+x[...,2]/2y[...,3]=x[...,1]+x[...,3]/2returnydefnms(boxes,scores,iou_thres):x1,y1,x2,y2=boxes.T areas=(x2-x1)*(y2-y1)order=scores.argsort()[::-1]keep=[]whileorder.size>0:i=order[0]keep.append(i)iforder.size==1:breakxx1=np.maximum(x1[i],x1[order[1:]])yy1=np.maximum(y1[i],y1[order[1:]])xx2=np.minimum(x2[i],x2[order[1:]])yy2=np.minimum(y2[i],y2[order[1:]])w=np.maximum(0.0,xx2-xx1)h=np.maximum(0.0,yy2-yy1)inter=w*h iou=inter/(areas[i]+areas[order[1:]]-inter+1e-9)inds=np.where(iou<=iou_thres)[0]order=order[inds+1]returnkeepdefpostprocess_yolov8(outputs,conf_thres=0.25,iou_thres=0.45):""" 常见 YOLOv8 ONNX 输出形态之一: outputs[0] shape: (1, 84, 8400) 或 (1, 8400, 84) 84 = 4(Box) + num_cls """out=outputs[0]out=np.squeeze(out,axis=0)ifout.shape[0]<out.shape[1]:out=out.T boxes=out[:,:4]cls_scores=out[:,4:]cls_conf=cls_scores.max(axis=1)cls_id=cls_scores.argmax(axis=1)mask=cls_conf>=conf_thres boxes,cls_conf,cls_id=boxes[mask],cls_conf[mask],cls_id[mask]ifboxes.shape[0]==0:returnnp.empty((0,4)),np.empty((0,)),np.empty((0,),dtype=np.int32)boxes=xywh2xyxy(boxes)keep=nms(boxes,cls_conf,iou_thres)returnboxes[keep],cls_conf[keep],cls_id[keep].astype(np.int32)defmain():ifnotos.path.exists(MODEL_PATH):raiseFileNotFoundError(f"模型不存在:{MODEL_PATH}")sess=ort.InferenceSession(MODEL_PATH,providers=["CPUExecutionProvider"])in_name=sess.get_inputs()[0].name cap=cv2.VideoCapture(DEVICE)ifnotcap.isOpened():raiseRuntimeError(f"无法打开摄像头:{DEVICE}(检查权限/驱动/占用)")frame_id=0fps_win=[]print("开始推理,按 Ctrl+C 退出。输出保存到 runs/ 目录。")try:whileTrue:ok,frame=cap.read()ifnotok:print("读帧失败,退出。")breakimg,r,(padw,padh)=letterbox(frame,IMG_SIZE)rgb=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)inp=rgb.astype(np.float32)/255.0inp=np.transpose(inp,(2,0,1))[None,...]t1=time.time()outputs=sess.run(None,{in_name:inp})boxes,scores,cls_ids=postprocess_yolov8(outputs,CONF_THRES,IOU_THRES)t2=time.time()# 映射回原图坐标ifboxes.shape[0]>0:boxes[:,[0,2]]-=padw boxes[:,[1,3]]-=padh boxes/=r boxes[:,[0,2]]=np.clip(boxes[:,[0,2]],0,frame.shape[1]-1)boxes[:,[1,3]]=np.clip(boxes[:,[1,3]],0,frame.shape[0]-1)vis=frame.copy()for(x1,y1,x2,y2),sc,cidinzip(boxes,scores,cls_ids):x1,y1,x2,y2=map(int,[x1,y1,x2,y2])cv2.rectangle(vis,(x1,y1),(x2,y2),(0,255,0),2)cv2.putText(vis,f"id={cid}{sc:.2f}",(x1,max(0,y1-6)),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,255,0),2)infer_ms=(t2-t1)*1000.0fps=1.0/max(1e-6,(t2-t1))fps_win.append(fps)iflen(fps_win)>30:fps_win.pop(0)cv2.putText(vis,f"Infer{infer_ms:.1f}ms FPS~{np.mean(fps_win):.1f}",(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.9,(255,0,0),2)# 限制写盘频率(避免 I/O 拖慢)ifframe_id%20==0:out_path=SAVE_DIR/f"frame_{frame_id:06d}.jpg"cv2.imwrite(str(out_path),vis)print(f"save:{out_path}det={len(boxes)}fps~{np.mean(fps_win):.1f}")frame_id+=1exceptKeyboardInterrupt:passfinally:cap.release()print("结束。")if__name__=="__main__":main()

运行:

cd~/defect_demosourcevenv/bin/activate python3 infer_cam_onnx.py

7. 常见问题

  • 摄像头打不开:先用第 3 节的gst-launch-1.0验证;确认是否被占用、权限是否足够。
  • 能取流但推理很慢:将写盘频率降到每 50 帧一张;将输入尺寸改小(320/416)验证;加速部分在(二)展开。
  • 输出框太多导致后处理慢:提高CONF_THRES;必要时先做 topK 再 NMS((四)会展开)。

📢下一篇介绍

至此,我们已经完成了高通QCS9100 上从摄像头取流、ONNX 模型推理、后处理到结果可视化的最小闭环。**下一篇**我们将切换到QNN/HTP,真正发挥 NPU 的加速能力,敬请期待!

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

http://www.jsqmd.com/news/473742/

相关文章:

  • 实测负荷数据(示例)
  • 北京上门回收老安宫牛黄丸、片仔癀!本草拾光商行高价收,变现快时效拉满 - 品牌排行榜单
  • 西门子PLC精确计算设备运行时间程序(1200PLC与1500PLC通用)——改良版实时时间比较法
  • C++学习日志——面向过程篇3.11
  • 架构2
  • ADRC双环自抗扰控制永磁同步电机矢量控制伺服系统Matlab仿真探索
  • IT系统全生命周期管理和运营方案(Word)
  • PYTHON学习笔记3
  • 代码随想录算法训练营第十天 | 用栈实现队列、 用队列实现栈、有效的括号、删除字符串中的所有相邻重复项
  • OFDM MQAM在衰落信道下误比特率性能仿真探索
  • python语法学习
  • Simulink双三相永磁同步电机控制仿真! 1.矢量控制,包括两种电机建模,VSD模型和双d...
  • STM32单片机开发的空气净化器:原理、设计与源码详解,适合开发人员
  • 探索多机器人协同编队避障算法:从人工势场到动态窗口
  • 从空白文档到合格初稿:Paperzz 毕业论文智能写作,让毕业生告别 “选题 - 文献 - 提纲” 三重焦虑
  • KPCA - ISSA - SVM分类预测:MATLAB实战与模型对比
  • Pyrene-PEG-NH2 氨基功能化芘荧光PEG活细胞成像与示踪探针
  • 产品推荐|40分区光控照明系统
  • 自动化测试中JSONPath 是解析复杂 JSON 响应的核心工具
  • binning模式下和normal模式下相同曝光参数相同场景加权亮度差异消除方案
  • LabVIEW图像处理框架核心结构示意图
  • 搞嵌入式开发的小伙伴应该都遇到过PID调参这个头疼的问题吧?今天咱们直接上干货,聊聊怎么在STM32上玩转PID自整定和温度控制。先扔个核心代码片段镇楼
  • HCSR04超声波测距仿真示例
  • 解决OpenWeatherMap API秘钥激活后仍无法使用
  • 基于STM32的电机控制器:Keil与Proteus的嵌入式之旅
  • 鸿蒙中 应用的权限(一)
  • 心理聊天App 5款产品实测对比,哪个更适合情绪内耗的你?
  • 内存涨价、供应不稳?嵌入式工程师必看:适合轻量级项目ARM选型与存储避坑指南
  • GESP C++一级认证完全指南:考点解析与备考策略
  • SpringBoot3实战集成mzt-biz-log,一行代码搞定业务日志记录