YOLOv7+双目实现三维跟踪(python)
- 1. 目标跟踪
- 2. 测距模块
- 2.1 测距原理
- 2.2 添加测距
- 3. 细节修改(可忽略)
- 4. 实验效果
相关链接
1. YOLOV5 + 双目测距(python)
2. YOLOV7 + 双目测距(python)
3. YOLOv5+双目实现三维跟踪(python)
3. 具体实现效果已在Bilibili发布,点击跳转
1. 目标跟踪
用yolov7实现跟踪步骤比较简单,去官网下载yolov7源码,然后下载跟踪模块相关代码,链接:https://download.csdn.net/download/qq_45077760/87712810
将下载的内容全部拖进yolov7-main文件夹里,把环境装好,然后运行代码 detect_or_track.py
此时如果不出问题就完成了普通检测
这里有几个常用知识需要注意的,我直接在以下代码作了注释
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--weights', nargs='+', type=str, default='yolov7.pt', help='model.pt path(s)')# 设置权重
parser.add_argument('--source', type=str, default='street.mp4', help='source') # file/folder, 0 for webcam 设置检测路径
parser.add_argument('--img-size', type=int, default=640, help='inference size (pixels)')
parser.add_argument('--conf-thres', type=float, default=0.25, help='object confidence threshold')
parser.add_argument('--iou-thres', type=float, default=0.45, help='IOU threshold for NMS')
parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
parser.add_argument('--view-img', action='store_true', help='display results')
parser.add_argument('--save-txt', action='store_true', help='save results to *.txt')
parser.add_argument('--save-conf', action='store_true', help='save confidences in --save-txt labels')
parser.add_argument('--nosave', action='store_true', help='do not save images/videos')#是否保存检测结果
parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --class 0, or --class 0 2 3') # 设置检测类别
parser.add_argument('--no-trace', action='store_true', help='don`t trace model')
parser.add_argument('--track', action='store_true', help='run tracking')#是否跟踪
parser.add_argument('--show-track', action='store_true', help='show tracked path') #显示跟踪轨迹
parser.add_argument('--show-fps', action='store_true', help='show fps')# 显示fps
parser.add_argument('--thickness', type=int, default=2, help='bounding box and font size thickness')
parser.add_argument('--seed', type=int, default=1, help='random seed to control bbox colors') #初始数字,直接改变目标方框颜色和序号
parser.add_argument('--nobbox', action='store_true', help='don`t show bounding box')
parser.add_argument('--nolabel', action='store_true', help='don`t show label')
parser.add_argument('--unique-track-color', action='store_true', help='show each track in unique color') # # 每条轨迹不同颜色
也可以用终端运行命令python detect_or_track.py --weight yolov7.pt --no-trace --view-img --source 1.mp4
--show-fps #显示fps
--seed 2 #初始数字,直接改变目标方框颜色和序号
--track #每个方框左上角有ID数字
--classes 0 1 # 只显示前两种类型 (总共80种在data/coco.yaml里)
--show-track #显示跟踪轨迹
--unique-track-color # 每条轨迹不同颜色
--nobbox
--nolabel
--nosave# 不保存,把上边那行删掉,会保存到XXX\yolov7\runs\detect\exp
2. 测距模块
2.1 测距原理
测距原理详见 双目三维测距(python)
2.2 添加测距
接下来调用测距代码到主代码 detect_or_track.py 文件中,先在代码开头导入库,添加
from stereo import stereoconfig
from stereo.stereo import stereo_40
from stereo.stereo import stereo_threading, MyThread
from yolov5.utils.plots import plot_one_box
我们需要将立体匹配等代码写进跟踪模块里,具体写法在我之前开源的 YOLOv5+双目测距(python) 这片文章里已经提及,这里就不再细讲,最后计算得到目标框的中心点坐标和距离对其进行显示,具体如下
for *xyxy, conf, cls in det:
global diatance
# to deep sort format
x_c, y_c, bbox_w, bbox_h = xyxy_to_xywh(*xyxy)
xywh_obj = [x_c, y_c, bbox_w, bbox_h]
xywh_bboxs.append(xywh_obj)
confs.append([conf.item()])
if (0 < xyxy[2] < 1280):
x_center = (xyxy[0] + xyxy[2]) / 2
y_center = (xyxy[1] + xyxy[3]) / 2
x_0 = int(x_center)
y_0 = int(y_center)
if (0 < x_0 < 1280):
x1 = xyxy[0]
x2 = xyxy[2]
y1 = xyxy[1]
y2 = xyxy[3]
if (accel_frame % fps_set == 0):
t3 = time.time() # stereo time end
thread.join()
points_3d = thread.get_result()
# gol.set_value('points_3d', points_3d)
t4 = time.time() # stereo time end
print(f'{s}Stereo Done. ({t4 - t3:.3f}s)')
a = points_3d[int(y_0), int(x_0), 0] / 1000
b = points_3d[int(y_0), int(x_0), 1] / 1000
c = points_3d[int(y_0), int(x_0), 2] / 1000
distance = ((a**2+b**2+c**2)**0.5)
if (distance != 0): ## Add bbox to image
label = f'{names[int(cls)]} {conf:.2f} '
text_xy_0 = "*"
print('点 (%d, %d) 的 %s 距离左摄像头的相对距离为 %0.2f m' % (x_center, y_center, label, distance))
text_dis_avg = "dis:%0.2fm" % distance
cv2.rectangle(im0, (int(x1 + (x2 - x1)), int(y1)),(int(x1 + (x2 - x1) + 5 + 100), int(y1 + 12)), colors[int(cls)],-1) # 画框存三维坐标
cv2.putText(im0, text_dis_avg, (int(x1 + (x2 - x1) + 5), int(y1 + 10)),cv2.FONT_HERSHEY_PLAIN, 1, (255, 255, 255), 2)
也可以把 if (distance != 0) 及其后边的代码删除,直接把 points_3d 设置成全局变量,在 draw_boxes 里显示,具体如下
def draw_boxes(img, bbox, identities=None, categories=None, confidences = None, names=None, colors = None):
global distance
for i, box in enumerate(bbox):
x1, y1, x2, y2 = [int(i) for i in box]
tl = opt.thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # line/font thickness
if (0 < x2 < 1280):
cat = int(categories[i]) if categories is not None else 0
id = int(identities[i]) if identities is not None else 0
color = colors[cat]
if not opt.nobbox:
cv2.rectangle(img, (x1, y1), (x2, y2), color, tl)
if not opt.nolabel:
#label = str(id) + ":" + names[cat] if identities is not None else f'{names[cat]} {confidences[i]:.2f}'
label = str(id) + ":"+ names[cat]+ " "+"dis:"+str(distance)+"m" if identities is not None else f'{names[cat]} {confidences[i]:.2f}'
tf = max(tl - 1, 1) # font thickness
t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]
c2 = x1 + t_size[0], y1 - t_size[1] - 3
cv2.rectangle(img, (x1, y1), c2, color, -1, cv2.LINE_AA) # filled
cv2.putText(img, label, (x1, y1 - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)
3. 细节修改(可忽略)
实时显示画面太大,我们对显示部分做了修改,这部分也可以不要,具体是把代码
if view_img:
cv2.imshow(str(p), im0)
cv2.waitKey(1) # 1 millisecond
替换成
if view_img:
cv2.namedWindow("Webcam", cv2.WINDOW_NORMAL)
cv2.resizeWindow("Webcam", 1280, 720)
cv2.moveWindow("Webcam", 0, 100)
cv2.imshow("Webcam", im0)
cv2.waitKey(1)
4. 实验效果
从实验效果可以看出来其实这里是存在一些问题的,虽然测距我只让他在左相机画面显示,但是跟踪的话两个相机画面同时进行了跟踪,估计是跟踪模块没有做改动,这一个细节后续也会去深入研究,大家如果有了解这一块如何修改的的也可以联系我
更多测距代码见博客主页, 源代码后续会开源…