因为我的毕业设计就是搞目标检测这一块的,前段时间好不容易实现了yolov5的目标检测,后来还需要实现目标测距,于是在B站和博客里不断摸索,效果很不理想,知识点零散,幸运的是最终琢磨懂了代码和原理。全文通俗易懂。
前提是你要会用yolov5实现目标检测,我是跟着一位博主学做出来的——目标检测—教你利用yolov5训练自己的目标检测模型 。重点是在B站里也有他做的 保姆级视频,本文着重讲解单目测距。 实现了yolov5检测之后直接去我的gitee上下载我的测距项目: yolov5-main。下载并解压项目到PyCharm中,配置上运行yolov5的环境,然后跑一遍detect.py,看看我的案例效果,成功运行后再跟着教程慢慢搞。
因为条件的限制,我没有选择双目测距来研究,其实单目和双目各有优缺点。它们的原理网上搜也是一大把,本文直接跳过原理讲解,我们来讲公式:
先来看看核心代码
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(其实就是利用到方框的像素高度)传进来,这个函数首先会根据公式计算出单位为英尺的距离,然后转换,最终得到单位为米的距离。
网上有说相机标定这个操作,我没有深入研究,貌似可以矫正图片,减小误差。我是直接跳过这个操作,影响不大。
下面讲一下怎么调试焦距,我用的是手机摄像头。
这个时候公式 D = (F*W)/P 的三个参数已经知道了F和W两个,这个P在下面2.的(4)里可以被计算出来。
# 改变显示图片大小(自定义函数)
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
(2)116行做一个判断,置信度低的就不要显示了,有时候地上一个图案都能被识别成人,用官方权重来检测,检测到的东西几乎都会被框上,这样会很杂,我们可以根据需求选择我们想框的东西,像我一样在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')
小学弟我才学疏浅,非计算机科班出身,对编程感兴趣,自学Java出身,因为毕业设计意外选到人工智能的课题,所以临时自学Python,然后慢慢接触人工智能。
本文章虽然通俗易懂,但是缺乏专业术语。
代码中能看到的中文注释我建议简单理解一遍。
若有不足,望大佬指教!