ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

树莓派ROS视觉跟踪小车实战:CamShift算法与双机配置

树莓派ROS视觉跟踪小车实战:CamShift算法与双机配置 简介基于机器人操作系统与开源计算机视觉库的视觉跟踪智能小车项目源码包面向机器人视觉、嵌入式开发及智能车竞赛学习者适合需要实现实时目标跟踪、掌握树莓派与虚拟机主从联调的读者。项目以树莓派作为主机接收USB摄像头采集的视频流借助Ubuntu虚拟机从机进行软件开发与调试并采用连续自适应均值漂移CamShift颜色概率模型算法在连续视频帧中动态调整跟踪窗口实现稳定准确的目标识别与跟随。压缩包内共8个文件涵盖工程源码、机器人操作系统节点配置、Python脚本、说明文档及附赠资料文件类型以txt、md、docx、py为主整体仅43KB轻量紧凑便于快速下载和部署。目前已有33人学习使用内容整理了项目目录结构与关键实现细节可帮助理解CamShift跟踪流程、机器人操作系统工作空间搭建、树莓派与虚拟机通信配置等难点适合作为课程设计、毕业设计或智能车项目的参考方案也可为停车场管理等场景提供视觉跟踪技术参考。 这阵子一直在折腾ROS小车终于把基于树莓派3B的视觉跟踪小车跑通了。整个项目说难不难但坑确实不少。树莓派3B作为主机负责图像采集和处理另一边用Ubuntu虚拟机当从机做远程调试和显示目标跟踪用OpenCV里的CamShift算法实时处理USB摄像头的视频流。这篇文章就是把这个项目的完整思路、配置步骤和调参过程整理出来给打算入门ROS视觉或者想要复现视觉目标小车的人一个参考。最终效果是小车能通过USB摄像头锁定一个颜色特征明显的目标在画面里实时框出来并根据目标偏移量控制底盘转向。如果你手上是树莓派4B或者只跑虚拟机这套逻辑也能直接用差别主要在性能余量上。下面我从整体设计开始讲尽量把每个选择背后的原因也说清楚。1. 项目整体设计先想清楚谁干活、谁盯着1.1 双机结构怎么分工树莓派干活虚拟机调试树莓派3B的CPU是四核A53跑Ubuntu MATE能接受但要是同时开桌面、跑摄像头采集、再做图像处理就会很吃力。所以我一开始就把机器分工想明白了树莓派3B作为ROS主机摄像头和运动控制都挂在它身上Ubuntu虚拟机作为从机承担代码编辑、Rviz显示和日志查看。为什么不把图像处理放到虚拟机道理很简单视频流经过WiFi传到虚拟机再处理延迟至少增加几十毫秒而且一旦网络抖动画面直接卡住。树莓派本地处理完只把目标位置、跟踪框这些结果发到虚拟机实时性要好很多。虚拟机的好处是调试方便桌面崩了不影响树莓派SSH进去改代码就行。这个架构对以后做多机协作也比较友好主从节点各自独立出问题容易定位。1.2 CamShift算法在树莓派上为什么够用选择CamShift不是因为它新而是因为它算力友好。CamShift全称Continuously Adaptive MeanShift本质是MeanShift的改进版。MeanShift会在颜色概率分布图上反复迭代寻找窗口内的质心CamShift则在每帧根据结果调整窗口大小和方向从而适应目标在画面中变大变小、旋转倾斜的情况。树莓派3B算力有限跑深度学习目标检测基本不现实而CamShift只依赖颜色直方图计算量很小640x480分辨率下也能跑到20帧左右。如果你的目标是颜色清晰、和环境区分明显的物体比如红色球、橙色锥桶CamShift是性价比很高的选择。哪怕你以后想换YOLO这个项目的图像采集、ROS通信和底盘控制部分仍然能复用不会白做。1.3 系统和软件版本怎么选才能少踩坑版本选型很关键强烈建议不要一股脑装最新版。树莓派3B我用的系统是Ubuntu MATE 16.04ROS版本是KineticOpenCV直接用系统自带3.2。虚拟机那边为了保持一致也用Ubuntu 16.04加Kinetic。如果非要用Ubuntu 20.04加ROS Noetic也完全可以但要注意OpenCV版本和cv_bridge的匹配这个后面专门说。当时我一开始总想着能装新版就装新版后来踩了不少坑其实在ROS生态里稳定压倒一切。刷好系统之后先把源改成国内源再装基础软件能省下大量时间。另外提醒一下如果你是树莓派3B系统镜像用armhf版本别下成64位否则后面装ROS会有兼容问题。2. 树莓派与虚拟机环境搭建实录2.1 树莓派ROS安装从换源到一键脚本树莓派3B安装ROS最简单的方式是用鱼香ROS一键安装脚本省去不少手动依赖的麻烦。不过一键脚本不是万能的如果手动装建议先换源然后按官方步骤添加ROS源安装ros-kinetic-desktop。这里要提醒树莓派是armhf架构ROS源要选对不要照抄x86的源。安装过程中如果编译功能包可能耗很长时间但这是正常的不要中途断电。装完之后把环境变量写进~/.bashrc运行roscd检查一下能否进入ROS目录。我当时手动装过一次后来为了验证一键脚本也重装过两种方式都能通。如果你是第一次接触ROS我推荐先手动装一遍这样对rosdep、catkin这些组件的关系会有直观理解后面排查问题会更有底。2.2 虚拟机Ubuntu从机配置网络和SSH虚拟机用VMware安装Ubuntu网络模式一定要选桥接保证虚拟机和树莓派在同一个局域网段。如果用NAT虚拟机可以访问外网但不容易被树莓派找到主从ROS通信会非常别扭。装好之后给虚拟机分配一个固定IP树莓派则通过路由器或手机热点分配IP。为了省事我在路由器上给树莓派MAC绑定了固定IP虚拟机设为静态IP。然后通过SSH从虚拟机连树莓派。Windows上可以用MobaXtermLinux虚拟机直接用ssh命令行就行。整个开发流程就是虚拟机里写代码scp或git同步到树莓派在树莓派上编译运行通过Rviz远程看画面。这个方案比直接在树莓派上写舒服太多也方便留日志。2.3 ROS主从通信配置一条命令定位问题ROS分布式通信只有一个master所有节点通过master互相发现。在这个项目里我让树莓派启动roscore虚拟机上的节点找树莓派注册。因此需要设置ROS_MASTER_URI和ROS_IP。在树莓派和虚拟机的~/.bashrc里写入export ROS_MASTER_URIhttp://192.168.1.100:11311 export ROS_IP192.168.1.101注意ROS_IP要写各自本机的IP树莓派上写树莓派的IP虚拟机上写虚拟机的IP千万别复制同一份。没有这个设置多网卡环境下ROS可能注册成错误的地址。测试方法很简单树莓派开roscore虚拟机运行rostopic list能列出话题就说明通了。如果出现连接问题先ping再查防火墙这两个地方最常见。3. 视觉跟踪核心链路从像素到控制量3.1 USB摄像头接入usb_cam和v4l2检查USB摄像头接入树莓派先运行lsusb看是否识别大部分免驱摄像头会显示UVC Camera。然后确认设备节点是否为/dev/video0。我用的usb_cam包launch文件里设置video_device为/dev/video0image_width和image_height设为640x480pixel_format设为mjpeg。如果摄像头支持MJPG优先用MJPG格式帧率会高一些。也可以用v4l2-ctl --list-formats-ext查看摄像头支持的格式。当时我手里还有一个CSI接口的OV5647摄像头模块树莓派也能用但驱动方式不同要用raspicam_node和USB摄像头不是一套方案。这个项目之所以选USB摄像头主要因为它即插即用换到虚拟机上也能直接调试通用性比CSI摄像头强很多。3.2 图像预处理为什么非要用HSV拿到图像之后不能直接丢给CamShift要先做预处理。首先是格式如果通过cv_bridge从ROS话题取图要把sensor_msgs::Image转成OpenCV的Mat。我习惯先把RGB转成HSV因为HSV对光照变化比RGB稳定颜色也更符合人眼直觉。接着做高斯模糊降低噪声再根据目标颜色范围用cv2.inRange生成二值掩膜。最后用开运算去掉零散噪点用闭运算补全目标内部的空洞。这一步做得好不好直接决定后面的反向投影质量。经验是宁可把阈值范围调得小一点也别让背景混进来否则CamShift窗口会被背景带走。所谓反向投影就是统计目标颜色的直方图然后回投到当前帧上得到每个像素属于目标的概率颜色越像目标灰度值越高。3.3 CamShift跟踪节点的核心代码解读核心代码我写成了Python节点接收usb_cam的image_raw话题初始化时让用户框选目标ROI统计HSV直方图然后每帧用calcBackProject得到概率图再用CamShift迭代。核心代码大致如下import cv2 import numpy as np # 初始化在首帧框选目标 roi cv2.selectROI(frame, frame, False) hsv_roi cv2.cvtColor(frame[y:yh, x:xw], cv2.COLOR_BGR2HSV) roi_hist cv2.calcHist([hsv_roi], [0], None, [16], [0, 180]) cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) term_crit (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1) while True: ret, frame cap.read() hsv cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) dst cv2.calcBackProject([hsv], [0], roi_hist, [0, 180], 1) ret, track_window cv2.CamShift(dst, track_window, term_crit) pts cv2.boxPoints(ret) pts np.int0(pts) cv2.polylines(frame, [pts], True, (0, 255, 0), 2) x, y ret[0] cv2.circle(frame, (int(x), int(y)), 5, (0, 0, 255), -1) cv2.imshow(track, frame)这里的ret是RotatedRect中心点就是目标位置。要控制小车的话把中心点与图像中心做差根据偏移发布cmd_vel做比例控制就行。CamShift输出的旋转矩形即使目标倾斜也能框住比单纯的外接矩形更贴合目标。4. 调参优化让CamShift在树莓派上跑得稳4.1 目标框怎么选第一帧ROI决定成败CamShift很依赖第一帧ROI。ROI选得准颜色直方图就干净。我在项目里用鼠标框选目标框选时尽量只框目标主体不要包含太多背景。如果框里的背景色和前景色接近直方图会被污染。调参时有个技巧在终端打印roi_hist的统计值观察哪个bin对应主要颜色也可以用颜色选择器在画面上手动取HSV上下限。目标颜色要鲜明红色、黄色、绿色都可以。纯白、纯黑很容易受光照影响跟踪效果不稳定。实测下来室内日光灯下红色目标最稳因为红色在背景中出现概率低而且HSV的H分量在0到180两端阈值好控制。如果你想跟踪的是人或者车辆这种复杂目标CamShift就不太合适建议换更高级的检测器。4.2 关键参数调整直方图bin数、迭代次数和核大小有三个参数对跟踪稳定性影响最大。直方图bin数我用的16。bin太少会丢失颜色信息太多则对噪声敏感。迭代终止条件里的count设为10eps设为1表示最多迭代10次或者窗口移动小于1像素就停止。开闭运算的核大小用3x3或5x5就够了太大容易把目标形状磨没。下面这个表是我整理的经验值可以参考但不要死记参数推荐值说明直方图bin数8-3216综合效果好TermCriteria count8-15太低会跟丢太高浪费算力TermCriteria eps1像素级收敛阈值高斯模糊核5x5去噪同时保留边缘形态学核3x3开闭运算统一用3x3分辨率320x240到640x480树莓派3B建议640x480CamShift本身用的是直方图反向投影不直接依赖硬阈值所以比固定inRange更抗光照变化。但如果场景的色相变化太剧烈还是要考虑动态更新roi_hist。4.3 实时性优化分辨率、帧率和传输压缩树莓派3B性能有限不能把所有帧都做全尺寸处理。我的优化措施有几条。一是用MJPG格式获取摄像头图降低USB带宽消耗。二是OpenCV处理前先缩放帧如果摄像头输出1280x720先缩到640x480再算。三是直方图反向投影和CamShift只处理感兴趣区域比如上一帧跟踪窗口是100x80搜索范围扩大20%变成120x96只在这个区域内计算速度会快不少。四是控制频率没必要太高。视觉跟踪loop跑20Hz但底盘控制发布10Hz就够避免电机频繁抖动。如果你需要把视频传到虚拟机查看用image_transport的compressed话题比raw话题省很多带宽。实际测试下来MJPG 640x480下树莓派3B大约18到22帧CPU占用70%左右能够满足实时跟踪。5. 踩坑记录常见问题与排查思路5.1 树莓派绿灯闪和启动异常绿灯持续闪烁且系统无法启动基本就是电源不足或者SD卡文件系统损坏。树莓派3B要求5V 2.5A不要用电脑USB口供电。我一开始用手机充电器供电功率不够只要摄像头一工作电流上来就重启。换了一个5V3A的适配器之后绿灯闪的情况就消失了。SD卡尽量选class10以上A1规格更好。刷完系统第一次启动时绿灯闪是正常初始化别急着断电。如果始终闪就用读卡器在电脑上重新刷系统或者用fsck修复分区。5.2 虚拟机与树莓派通信不上虚拟机与树莓派ROS通信不上十个有九个是网络模式问题。虚拟机NAT模式下树莓派无法主动访问虚拟机所以必须改成桥接。其次是ROS_MASTER_URI和ROS_IP不一致。还有一个隐蔽问题虚拟机里可能有多块网卡比如VMware生成的VMnet8和实际以太网卡ROS会自动选择其中一块这时候必须手动指定ROS_IP。排查顺序建议是这样的现象原因解法ping不通NAT模式或不在同一网段改为桥接固定IP能ping但rostopic list失败ROS_MASTER_URI或ROS_IP未设置检查~/.bashrc并sourcerostopic list有但Rviz无数据话题是compressed或Frame错误正确订阅compressed设置Fixed Frame如果话题有数据但Rviz不显示检查Fixed Frame设置和话题类型。用rostopic echo /tracker/position能看到实时数据这比干瞪眼快多了。5.3 OpenCV和cv_bridge版本冲突OpenCV版本冲突是另一个重灾区。树莓派上如果手动编译OpenCV时间很长我后来直接在Kinetic里用系统自带的OpenCV 3.2python-opencv和cv_bridge都能匹配。虚拟机上如果装了较新的opencv-pythonimport cv2时可能和ROS的cv_bridge链接到不同的OpenCV库导致段错误甚至直接崩溃。解决方法是使用ROS自带的Python环境或者把cv_bridge重新编译成与当前OpenCV版本兼容。如果是NoeticOpenCV4是默认很多旧代码里CV_BGR2HSV要改成COLOR_BGR2HSV编译报错基本都是这个原因。想装opencv-contrib-python的话可以指定版本并配合国内源安装省时间。但要注意只装到虚拟环境里尽量别和系统Python混用。5.4 CamShift跟丢和误跟踪CamShift最常见的问题是目标快速移动时跟丢因为目标一下子跑出了搜索范围。解决办法是先做运动预测比如用卡尔曼滤波估计下一帧目标位置CamShift从预测位置附近开始搜索搜索范围不用太大丢失概率能明显降低。其次是光照变化导致颜色偏差可以在每帧跟踪成功后适当用当前跟踪框内的HSV直方图更新roi_hist但更新权重不要太大比如新直方图占0.1否则会逐渐漂移到背景。还有一个问题是目标颜色和背景颜色接近这种情况需要在预处理阶段把背景颜色范围排除。我在项目里加了一个简单判断如果连续三帧概率图最大值低于阈值就把跟踪状态置为lost小车停在原地避免盲目乱跑。有时候系统“看起来没坏”比“报错”更讨厌因为你会花半天时间怀疑算法其实只是颜色阈值不对。最后再分享一点个人体会。CamShift这个算法不算新但它把颜色直方图、反向投影、均值漂移这套思路串得非常完整非常适合作为ROS视觉小车的第一个跟踪算法。我在这个项目里栽过的坑大多数不是算法本身而是环境配置和主从通信。如果你能把树莓派和虚拟机这套双机环境理顺后面再上目标检测、导航规划都会顺手很多。项目源码我整理成了R.zip里面包含树莓派端的ros_ws工作空间、虚拟机端调试脚本和摄像头相关工具需要的可以直接参考。祝各位早日跑起来。本文还有配套的精品资源点击获取
返回列表