YOLO小车跟踪
-
yolo跟踪代码:
https://download.csdn.net/download/zhuchen88988/20175153?spm=1001.2014.3001.5501
-
小车博客:
https://editor.csdn.net/md/?articleId=118612242
-
YOLOv3模型采用opencv dnn方式导入神经网络权重,再使用opencv读取视频流并转换为标准block接口进行前向传播。最后输出结果列表中存在物体质心,物体大小,物体标签置信度等等,将数据提出再进行画框。如果想要追踪目标就在循环中,判断标签是否属于要找的那个标签。
-
详细opencv实现yoloV3可以看
https://www.bilibili.com/video/BV18B4y1c7r4?p=11
oepncv使用Yolo注意点
- 由于使用树莓派motion推流的网络摄像头,python读取视频如果处理不及时会造成极大程度卡顿,延时。
所以想要解决卡顿问题需要使用重新编译源码的opencv gpu版本,在pip以及anaconda中中下载的opencv是无法使用GPU的。想要使用GPU版本opencv必须 安装cuda以及cudnn,通过cmake +vs 编译出来。网上有很多教程,不过可能会失败,如果想要一次成功,注意opencv版本和vs的版本如果opencv源码版本比较新,如4以上。建议vs版本也要在2016以上,cuda和cudnn版本也要比较新。反之 opencv在3.2以下,建议vs版本也要在2016以下,cuda,cudnn版本也要与之对应来。这样成功率比较高。 - cmake配置opencv源码时候会出现github连不上的问题,经过百度可以手动下载下来,修改本地文件,或者,修改下载url,在github后加个s。或者直接翻墙。均可以解决这个问题
- 还有一种解决延时的方法,是开启python多线程,一个线程读取视频流,另一线程yolo识别。读取视频流的线程做缓冲区,如果,yolo识别的结果反馈很慢,就丢弃后面的视频帧,这样也可以解决一些卡顿问题,但是这样会造成识别偶尔出现没有识别到目标的现象。
- yolov3模型有好几个版本,我使用320分辨率,分辨率越高的版本识别效果越好,但是处理速度越慢。yolov3有一个最低配版本为yolo-tiny,网上有人在树莓派上使用神经网络加速棒可以在本地运行yolov3-tiny网络,不过帧率不搞。本文使用的是yolov3-320版本,GPU opencv帧率稳定在30帧左右。
通讯协议控制小车
- python使用struct.pack函数打包字节流,并且可以指定大小端。非常方便。通讯协议按照我之前的博客
https://blog.csdn.net/zhuchen88988/article/details/118637714?spm=1001.2014.3001.5501
- 控制通讯源代码都封装成类在ROS_Car目录文件下。在Struct.py中可以看到其用法
- 字节流的CRC校验还是用的C语言,通过MinGW 64(python 也是64位)编译出.so动态库,使用加载动态库的方法调用C语言的函数库。详细可以百度python调用C语言。当然python也是有CRC16校验库的,也可以通过python库实现。
小车跟踪
- 小车实现跟踪目标原理即为,将摄像头识别到的目标一直处于镜头中央。yolo3前向传播后的结果中有物体的质心,即使得质心在屏幕中央即可。
- 由于小车不能在Y轴方向上改变摄像头位置,所以只需要改变摄像头X轴(即左右轮速改变摄像头),使得物体质心处于摄像头中央,这可以使用PID进行调节,具体公式如下:V=Kperr+Kderr_last(没有加入积分),err即为目标与摄像头正中央水平轴X差距,PID实现如下:
def PIDX_result(Cx,Kp,Kd,PID_outputs):
Ox = 320 #中点X位置
global Vl_dir
global Vr_dir
global err_last
global Vx
if Cx !=0:
if (Cx-Ox)<0:
print("偏左")
#偏左,右轮前向,左轮反向(原地左转向)
Vl_dir=0x02
Vr_dir=0x01
elif (Cx-Ox)>0:
print("偏右")
#偏右,左轮向后,前轮相反(原地右转向)
Vl_dir=0x01
Vr_dir=0x02
else :
print("CX无值")
Cx=320
Vl_dir = 0x00
Vr_dir = 0x00
err=Cx-Ox
err_D=err-err_last
Vx=abs(float(Kp*err +Kd*err_D))
err_last = err
print("Vl_dir:",Vl_dir)
print("Vr_dir:", Vr_dir)
PID_outputs[0]=Vl_dir
PID_outputs[1]=Vr_dir
PID_outputs[2]=Vx
return PID_outputs
- 同理如果为飞控的话,可以加上Y轴,达到完美的跟踪目标。