基于yolov5的目标检测和单目测距

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

废话在前头

  因为我的毕业设计就是搞目标检测这一块的前段时间好不容易实现了yolov5的目标检测后来还需要实现目标测距于是在B站和博客里不断摸索效果很不理想知识点零散幸运的是最终琢磨懂了代码和原理。全文通俗易懂。

正文开始

1、最终目的

  实现目标检测跟踪和目标测距

2、实现过程

2.1 实现的前提

  前提是你要会用yolov5实现目标检测我是跟着一位博主学做出来的——目标检测—教你利用yolov5训练自己的目标检测模型 。重点是在B站里也有他做的 保姆级视频本文着重讲解单目测距。 实现了yolov5检测之后直接去我的gitee上下载我的测距项目: yolov5-main。下载并解压项目到PyCharm中配置上运行yolov5的环境然后跑一遍detect.py看看我的案例效果成功运行后再跟着教程慢慢搞。请添加图片描述

2.2 知识点简要梳理

  因为条件的限制我没有选择双目测距来研究其实单目和双目各有优缺点。它们的原理网上搜也是一大把本文直接跳过原理讲解我们来讲公式

D = (F*W)/P
其中D是目标到摄像机的距离(最终要推测的距离, F是摄像机焦距根据下面教程来调试自己的镜头焦距, W是目标的宽度或者高度看情况来定行人检测一般以人的身高为基准, P是指目标在图像中所占据的x方向像素宽或者y方向像素高程序来计算。

2.3 单目测距代码

  先来看看核心代码

foc = 1810.0        # 镜头焦距
real_hight_person = 64.96   # 行人高度,注意单位是英寸

# 自定义函数单目测距
def detect_distance_person(h):
    dis_inch = (real_hight_person * foc) / (h - 2)
    dis_cm = dis_inch * 2.54
    dis_cm = int(dis_cm)
    dis_m = dis_cm/100
    return dis_m

简单理解一下代码定好焦距通过下一步调试可得和行人高度这里定一般人的身高我定165cm可以调单位为英寸然后在调用这个测距函数的时候把行人所占据的像素高度h其实就是利用到方框的像素高度传进来这个函数首先会根据公式计算出单位为英尺的距离然后转换最终得到单位为米的距离。

2.4 调试焦距

网上有说相机标定这个操作我没有深入研究貌似可以矫正图片减小误差。我是直接跳过这个操作影响不大。
下面讲一下怎么调试焦距我用的是手机摄像头。

  1. 先是准备一张A4纸横放在地板上或者别的东西上面要纯色为背景
  2. 用卷尺量出60cm的高度或者用棍子画出60cm的高度将手机打开录像横拍这个时候就不要放大镜头了垂直方正的将A4纸录十几秒的视频拍到的A4纸尽量不能歪;请添加图片描述
  3. 将视频放到项目的test目录里在detect_A4.py的第13行代码换上这个视频。运行detect_A4.py首先看一下有没有绿色的矩形出现并包裹住A4纸如果没有或者有但是明显包裹不紧的话就调节25行代码的阈值反复尝试直到矩形出现并包裹紧A4纸。这个时候可以看到图像左上角有数值这个就是A4纸到镜头的推测距离我们需要通过调节foc焦距参数让左上角这个数值接近60cm最终的foc焦距就是你这个视频的焦距了往后检测视频就用这个焦距而且检测的视频都是用这个焦距拍出来的。

2.5 拿到焦距就可以做目标测距了

2.5.1 讲一下总体思路

这个时候公式 D = (F*W)/P 的三个参数已经知道了F和W两个这个P在下面2.的4里可以被计算出来。

  1. 我在utils目录下定义了一个distance.py, 它的功能就是测距我在里边定义了两个测距模型一个是测人的一个是测车的这个时候先把之前调试好的焦距写在foc参数里行人和车的高度只是大概数值单位为英寸自己可以改
  2. 然后来到根目录下的detect.py这个文件我在基础上做了修改讲一下改了哪些。
    1第60行定义了一个函数以1200为宽的比例更改显示图像的大小因为原本的这个yolov5项目是按原图像显示的按我的焦距拍出来的视频会撑爆整个屏幕所以要缩小显示这个函数会在150行显示的时候被调用
# 改变显示图片大小自定义函数
    def cv_show(p, im0):
        height, width = im0.shape[:2]
        a = 1200 / width  # 宽为1200计算比例
        size = (1200, int(height * a))

        img_resize = cv2.resize(im0, size, interpolation=cv2.INTER_AREA)
        cv2.imshow(p, img_resize)
        cv2.waitKey(1)  # 1 millisecond

2116行做一个判断置信度低的就不要显示了有时候地上一个图案都能被识别成人用官方权重来检测检测到的东西几乎都会被框上这样会很杂我们可以根据需求选择我们想框的东西像我一样在118行和131行各做了一个判断分别是判断是不是人和车是的话就框出来并做相应处理128行调用的plot_one_box就是画框的函数

if conf2 > 0.4:   # 置信度小于0.4时不显示
	# person显示person标签的框并单独做person的测距
	if names[int(cls)] == 'person':
plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3,
                                             name=names[int(cls)])     # 画框函数

4这个函数在utils里的polts.py里我们来到polts.py里的59行我给这个函数添加了一个参数name在画框的时候函数会根据name是人还是车进行相应的测距函数调用68行和70行参数h是目标的高度63~65行通过方框坐标计算得出所调用的测距函数也就是前面我定义好的distance.py里边的。然后71行就是在原本的方框标签上追加我们测距得到的距离数据

def plot_one_box(x, img, color=None, label=None, line_thickness=3, name=None):
c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))   # 传过来的x包含有框的两个对角坐标
# w = int(x[2]) - int(x[0])   # 框的宽
h = int(x[3]) - int(x[1])     # 框的高
dis_m = 1.00
    if name == 'person':    # 根据标签名称调用不同函数计算距离
        dis_m = detect_distance_person(h)
    elif name == 'car':
        dis_m = detect_distance_car(h)
    label += f'  {dis_m}m'   # 在标签后追加距离

5这点不是很重要detect.py189行是否保存检测结果到runs/detect目录下我这里关闭了省储存这点根据需求来改需要保存就把它改成store_true然后在runs/detect目录下最后一个exp里找因为每运行一次detect.py都会生成一个exp文件最后一次运行结果自然保存在最后一个exp里

# store_true为保存视频或者图片路径为runs/detect
parser.add_argument('--nosave', action='store_false', help='do not save images/videos')   
  1. 总结就是基于yolov5的检测调用我们定义的测距函数拿到检测距离之后把距离追加到方框的标签后面。
2.5.1 实测自己的视频
  1. 自己用拍摄A4纸的方法到路边横屏拍摄视频相机到腰的位置拍点人或者车注意不能改变焦距来拍用拍摄A4纸的状态来拍。要问为什么不能竖屏拍我只能说我竖屏拍了视频传到项目里运行显示的图像会上下颠倒不懂是什么原因
  2. 拍好视频后把视频传电脑里复制到项目data/videos目录下重命名一下其实放哪里都无所谓等会路径写对就好。
  3. 来到detect.py的181行更改数据源改成刚刚那个视频的路径。
  4. 见证奇迹的时刻到了运行detect.py看看效果。

3、后语

  小学弟我才学疏浅非计算机科班出身对编程感兴趣自学Java出身因为毕业设计意外选到人工智能的课题所以临时自学Python然后慢慢接触人工智能。
  本文章虽然通俗易懂但是缺乏专业术语。
  代码中能看到的中文注释我建议简单理解一遍。
  若有不足望大佬指教

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“基于yolov5的目标检测和单目测距” 的相关文章