兰州网站优化服务,沈阳seo按天计费,金蝶软件收费价目表,宣传片拍摄哪个好YOLOv5单目测量尺寸#xff08;python#xff09; 1. 相关配置2. 测距原理3. 相机标定3.1#xff1a;标定方法1#xff08;针对图片#xff09;3.2#xff1a;标定方法2#xff08;针对视频#xff09; 4. 相机测距4.1 测距添加4.2 细节修改#xff08;可忽略#xf… YOLOv5单目测量尺寸python 1. 相关配置2. 测距原理3. 相机标定3.1标定方法1针对图片3.2标定方法2针对视频 4. 相机测距4.1 测距添加4.2 细节修改可忽略4.3 主代码 5. 实验效果 相关链接 1. YOLOV5 单目测距python 2. YOLOV7 单目测距python
本篇博文工程源码下载在文章末尾
1. 相关配置
系统win 10 YOLO版本yolov5 6.1 电脑显卡NVIDIA 2080TiCPU也可以跑GPU只是起到加速推理效果
2. 测距原理
单目测量尺寸原理和测距原理正好相反但是需要固定相机距离目标的距离然后把单目测距公式 D (F*W)/P 反过来求目标的长宽即可 W_True (D*W)/FH_True (D*H)/F其中D是目标到摄像机的距离, 是摄像机焦距焦距需要自己进行标定获取, W是目标的像素点宽度H是目标的像素点高度
了解基本原理后下边就进行实操阶段
3. 相机标定
3.1标定方法1针对图片
如果检测图片可以参考张学友标定法通过拍摄棋盘格获取相机的焦距
3.2标定方法2针对视频
直接使用代码获得焦距需要提前拍摄一个矩形物体拍摄时候相机固定距离被拍摄物体自行设定并一直保持此距离背景为纯色不要出现杂物最后将拍摄的视频用以下代码检测
import cv2win_width 1920
win_height 1080
mid_width int(win_width / 2)
mid_height int(win_height / 2)foc 1990.0 # 根据教程调试相机焦距
real_wid 9.05 # A4纸横着的时候的宽度视频拍摄A4纸要横拍镜头横A4纸也横
font cv2.FONT_HERSHEY_SIMPLEX
w_ok 1capture cv2.VideoCapture(5.mp4)
capture.set(3, win_width)
capture.set(4, win_height)while (True):ret, frame capture.read()# frame cv2.flip(frame, 1)if ret False:breakgray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)gray cv2.GaussianBlur(gray, (5, 5), 0)ret, binary cv2.threshold(gray, 140, 200, 60) # 扫描不到纸张轮廓时要更改阈值直到方框紧密框住纸张kernel cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))binary cv2.dilate(binary, kernel, iterations2)contours, hierarchy cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# cv2.drawContours(frame, contours, -1, (0, 255, 0), 2) # 查看所检测到的轮框for c in contours:if cv2.contourArea(c) 1000: # 对于矩形区域只显示大于给定阈值的轮廓所以一些微小的变化不会显示。对于光照不变和噪声低的摄像头可不设定轮廓最小尺寸的阈值continuex, y, w, h cv2.boundingRect(c) # 该函数计算矩形的边界框if x mid_width or y mid_height:continueif (x w) mid_width or (y h) mid_height:continueif h w:continueif x 0 or y 0:continueif x win_width or y win_height:continuew_ok wcv2.rectangle(frame, (x 1, y 1), (x w_ok - 1, y h - 1), (0, 255, 0), 2)dis_inch (real_wid * foc) / (w_ok - 2)dis_cm dis_inch * 2.54# os.system(cls)# print(Distance : , dis_cm, cm)frame cv2.putText(frame, %.2fcm % (dis_cm), (5, 25), font, 0.8, (0, 255, 0), 2)frame cv2.putText(frame, , (mid_width, mid_height), font, 1.0, (0, 255, 0), 2)cv2.namedWindow(res, 0)cv2.namedWindow(gray, 0)cv2.resizeWindow(res, win_width, win_height)cv2.resizeWindow(gray, win_width, win_height)cv2.imshow(res, frame)cv2.imshow(gray, binary)c cv2.waitKey(40)if c 27: # 按退出键esc关闭窗口breakcv2.destroyAllWindows()反复调节 ret, binary cv2.threshold(gray, 140, 200, 60)这一行里边的三个参数直到线条紧紧包裹住你所拍摄视频的物体然后调整相机焦距直到左上角距离和你拍摄视频时相机到物体的距离接近为止 然后将上述步骤得到的相机焦距以及镜头距离目标的距离写进测距代码distance.py文件里
foc 1998.0 # 镜头焦距
dis 709 # 镜头距离目标距离英寸# 自定义函数单目测距
def chicun(w,h):w_inch (dis * w) / focw_cm w_inch * 2.54w_cm int(w_cm)w_m w_cm/100h_inch (dis * h) / foch_cm h_inch * 2.54h_cm int(h_cm)h_m h_cm / 100return w_m,h_m4. 相机测距
4.1 测距添加
主要是把测距部分加在了画框附近首先提取边框的像素点坐标然后计算边框像素点宽度W和高度H
for *xyxy, conf, cls in reversed(det):if save_txt: # Write to filexywh (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywhline (cls, *xywh, conf) if save_conf else (cls, *xywh) # label formatwith open(txt_path .txt, a) as f:f.write((%g * len(line)).rstrip() % line \n)if save_img or save_crop or view_img: # Add bbox to imagex1 int(xyxy[0])y1 int(xyxy[1])x2 int(xyxy[2])y2 int(xyxy[3])h y2-y1w x2-x1if names[int(cls)] person:c int(cls) # integer class 整数类 1111111111label None if hide_labels else (names[c] if hide_conf else f{names[c]} {conf:.2f}) # 111w_m, h_m chicun(w, h)label f {w_m}mlabel f {h_m}mtxt {0}.format(label)# annotator.box_label(xyxy, txt, color(255, 0, 255))annotator.box_label(xyxy, txt, colorcolors(c, True))if save_crop:save_one_box(xyxy, imc, filesave_dir / crops / names[c] / f{p.stem}.jpg, BGRTrue)4.2 细节修改可忽略
到上述步骤就已经实现了单目测距过程下边是一些小细节修改可以不看 为了实时显示画面对运行的py文件点击编辑配置在形参那里输入–view-img --save-txt 但实时显示画面太大我们对显示部分做了修改这部分也可以不要具体是把代码
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.3 主代码
# YOLOv5 by Ultralytics, GPL-3.0 licenseRun inference on images, videos, directories, streams, etc.Usage - sources:$ python path/to/detect.py --weights yolov5s.pt --source 0 # webcamimg.jpg # imagevid.mp4 # videopath/ # directorypath/*.jpg # globhttps://youtu.be/Zgi9g1ksQHc # YouTubertsp://example.com/media.mp4 # RTSP, RTMP, HTTP streamUsage - formats:$ python path/to/detect.py --weights yolov5s.pt # PyTorchyolov5s.torchscript # TorchScriptyolov5s.onnx # ONNX Runtime or OpenCV DNN with --dnnyolov5s.xml # OpenVINOyolov5s.engine # TensorRTyolov5s.mlmodel # CoreML (MacOS-only)yolov5s_saved_model # TensorFlow SavedModelyolov5s.pb # TensorFlow GraphDefyolov5s.tflite # TensorFlow Liteyolov5s_edgetpu.tflite # TensorFlow Edge TPU
import argparse
import os
import sys
from pathlib import Pathimport cv2
import torch
import torch.backends.cudnn as cudnnFILE Path(__file__).resolve()
ROOT FILE.parents[0] # YOLOv5 root directory
if str(ROOT) not in sys.path:sys.path.append(str(ROOT)) # add ROOT to PATH
ROOT Path(os.path.relpath(ROOT, Path.cwd())) # relativefrom models.common import DetectMultiBackend
from utils.datasets import IMG_FORMATS, VID_FORMATS, LoadImages, LoadStreams
from utils.general import (LOGGER, check_file, check_img_size, check_imshow, check_requirements, colorstr,increment_path, non_max_suppression, print_args, scale_coords, strip_optimizer, xyxy2xywh)
from utils.plots import Annotator, colors, save_one_box
from utils.torch_utils import select_device, time_sync
from distance import person_distance, car_distance, chicuntorch.no_grad()
def run(weightsROOT / yolov5s.pt, # model.pt path(s)sourceROOT / data/images, # file/dir/URL/glob, 0 for webcamdataROOT / data/coco128.yaml, # dataset.yaml pathimgsz(640, 640), # inference size (height, width)conf_thres0.25, # confidence thresholdiou_thres0.45, # NMS IOU thresholdmax_det1000, # maximum detections per imagedevice, # cuda device, i.e. 0 or 0,1,2,3 or cpuview_imgFalse, # show resultssave_txtFalse, # save results to *.txtsave_confFalse, # save confidences in --save-txt labelssave_cropFalse, # save cropped prediction boxesnosaveFalse, # do not save images/videosclassesNone, # filter by class: --class 0, or --class 0 2 3agnostic_nmsFalse, # class-agnostic NMSaugmentFalse, # augmented inferencevisualizeFalse, # visualize featuresupdateFalse, # update all modelsprojectROOT / runs/detect, # save results to project/namenameexp, # save results to project/nameexist_okFalse, # existing project/name ok, do not incrementline_thickness3, # bounding box thickness (pixels)hide_labelsFalse, # hide labelshide_confFalse, # hide confidenceshalfFalse, # use FP16 half-precision inferencednnFalse, # use OpenCV DNN for ONNX inference):source str(source)save_img not nosave and not source.endswith(.txt) # save inference imagesis_file Path(source).suffix[1:] in (IMG_FORMATS VID_FORMATS)is_url source.lower().startswith((rtsp://, rtmp://, http://, https://))webcam source.isnumeric() or source.endswith(.txt) or (is_url and not is_file)if is_url and is_file:source check_file(source) # download# Directoriessave_dir increment_path(Path(project) / name, exist_okexist_ok) # increment run(save_dir / labels if save_txt else save_dir).mkdir(parentsTrue, exist_okTrue) # make dir# Load modeldevice select_device(device)model DetectMultiBackend(weights, devicedevice, dnndnn, datadata)stride, names, pt, jit, onnx, engine model.stride, model.names, model.pt, model.jit, model.onnx, model.engineimgsz check_img_size(imgsz, sstride) # check image size# Halfhalf (pt or jit or onnx or engine) and device.type ! cpu # FP16 supported on limited backends with CUDAif pt or jit:model.model.half() if half else model.model.float()# Dataloaderif webcam:view_img check_imshow()cudnn.benchmark True # set True to speed up constant image size inferencedataset LoadStreams(source, img_sizeimgsz, stridestride, autopt)bs len(dataset) # batch_sizeelse:dataset LoadImages(source, img_sizeimgsz, stridestride, autopt)bs 1 # batch_sizevid_path, vid_writer [None] * bs, [None] * bs# Run inferencemodel.warmup(imgsz(1 if pt else bs, 3, *imgsz), halfhalf) # warmupdt, seen [0.0, 0.0, 0.0], 0for path, im, im0s, vid_cap, s in dataset:t1 time_sync()im torch.from_numpy(im).to(device)im im.half() if half else im.float() # uint8 to fp16/32im / 255 # 0 - 255 to 0.0 - 1.0if len(im.shape) 3:im im[None] # expand for batch dimt2 time_sync()dt[0] t2 - t1# Inferencevisualize increment_path(save_dir / Path(path).stem, mkdirTrue) if visualize else Falsepred model(im, augmentaugment, visualizevisualize)t3 time_sync()dt[1] t3 - t2# NMSpred non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_detmax_det)dt[2] time_sync() - t3# Second-stage classifier (optional)# pred utils.general.apply_classifier(pred, classifier_model, im, im0s)# Process predictionsfor i, det in enumerate(pred): # per imageseen 1if webcam: # batch_size 1p, im0, frame path[i], im0s[i].copy(), dataset.counts f{i}: else:p, im0, frame path, im0s.copy(), getattr(dataset, frame, 0)p Path(p) # to Pathsave_path str(save_dir / p.name) # im.jpgtxt_path str(save_dir / labels / p.stem) ( if dataset.mode image else f_{frame}) # im.txts %gx%g % im.shape[2:] # print stringgn torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwhimc im0.copy() if save_crop else im0 # for save_cropannotator Annotator(im0, line_widthline_thickness, examplestr(names))if len(det):# Rescale boxes from img_size to im0 sizedet[:, :4] scale_coords(im.shape[2:], det[:, :4], im0.shape).round()# Print resultsfor c in det[:, -1].unique():n (det[:, -1] c).sum() # detections per classs f{n} {names[int(c)]}{s * (n 1)}, # add to string# Write resultsfor *xyxy, conf, cls in reversed(det):if save_txt: # Write to filexywh (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywhline (cls, *xywh, conf) if save_conf else (cls, *xywh) # label formatwith open(txt_path .txt, a) as f:f.write((%g * len(line)).rstrip() % line \n)if save_img or save_crop or view_img: # Add bbox to imagex1 int(xyxy[0])y1 int(xyxy[1])x2 int(xyxy[2])y2 int(xyxy[3])h y2-y1w x2-x1if names[int(cls)] person:c int(cls) # integer class 整数类 1111111111label None if hide_labels else (names[c] if hide_conf else f{names[c]} {conf:.2f}) # 111#dis_m person_distance(h)#label f {dis_m}mw_m, h_m chicun(w, h)label f {w_m}mlabel f {h_m}mtxt {0}.format(label)# annotator.box_label(xyxy, txt, color(255, 0, 255))annotator.box_label(xyxy, txt, colorcolors(c, True))if names[int(cls)] car:c int(cls) # integer class 整数类 1111111111label None if hide_labels else (names[c] if hide_conf else f{names[c]} {conf:.2f}) # 111dis_m car_distance(h)label f {dis_m}mtxt {0}.format(label)# annotator.box_label(xyxy, txt, color(255, 0, 255))annotator.box_label(xyxy, txt, colorcolors(c, True))if save_crop:save_one_box(xyxy, imc, filesave_dir / crops / names[c] / f{p.stem}.jpg, BGRTrue)# Stream resultsim0 annotator.result()if view_img:cv2.imshow(str(p), im0)cv2.waitKey(1) # 1 millisecondif 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)# Save results (image with detections)if save_img:if dataset.mode image:cv2.imwrite(save_path, im0)else: # video or streamif vid_path[i] ! save_path: # new videovid_path[i] save_pathif isinstance(vid_writer[i], cv2.VideoWriter):vid_writer[i].release() # release previous video writerif vid_cap: # videofps vid_cap.get(cv2.CAP_PROP_FPS)w int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))h int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))else: # streamfps, w, h 30, im0.shape[1], im0.shape[0]save_path str(Path(save_path).with_suffix(.mp4)) # force *.mp4 suffix on results videosvid_writer[i] cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*mp4v), fps, (w, h))vid_writer[i].write(im0)# Print time (inference-only)LOGGER.info(f{s}Done. ({t3 - t2:.3f}s))# Print resultst tuple(x / seen * 1E3 for x in dt) # speeds per imageLOGGER.info(fSpeed: %.1fms pre-process, %.1fms inference, %.1fms NMS per image at shape {(1, 3, *imgsz)} % t)if save_txt or save_img:s f\n{len(list(save_dir.glob(labels/*.txt)))} labels saved to {save_dir / labels} if save_txt else LOGGER.info(fResults saved to {colorstr(bold, save_dir)}{s})if update:strip_optimizer(weights) # update model (to fix SourceChangeWarning)def parse_opt():parser argparse.ArgumentParser()parser.add_argument(--weights, nargs, typestr, defaultROOT / yolov5s.pt, helpmodel path(s))parser.add_argument(--source, typestr, defaultROOT / data/images/2.mp4, helpfile/dir/URL/glob, 0 for webcam)parser.add_argument(--data, typestr, defaultROOT / data/coco128.yaml, help(optional) dataset.yaml path)parser.add_argument(--imgsz, --img, --img-size, nargs, typeint, default[640], helpinference size h,w)parser.add_argument(--conf-thres, typefloat, default0.25, helpconfidence threshold)parser.add_argument(--iou-thres, typefloat, default0.45, helpNMS IoU threshold)parser.add_argument(--max-det, typeint, default1000, helpmaximum detections per image)parser.add_argument(--device, default, helpcuda device, i.e. 0 or 0,1,2,3 or cpu)parser.add_argument(--view-img, actionstore_true, helpshow results)parser.add_argument(--save-txt, actionstore_true, helpsave results to *.txt)parser.add_argument(--save-conf, actionstore_true, helpsave confidences in --save-txt labels)parser.add_argument(--save-crop, actionstore_true, helpsave cropped prediction boxes)parser.add_argument(--nosave, actionstore_true, helpdo not save images/videos)parser.add_argument(--classes, nargs, typeint, helpfilter by class: --classes 0, or --classes 0 2 3)parser.add_argument(--agnostic-nms, actionstore_true, helpclass-agnostic NMS)parser.add_argument(--augment, actionstore_true, helpaugmented inference)parser.add_argument(--visualize, actionstore_true, helpvisualize features)parser.add_argument(--update, actionstore_true, helpupdate all models)parser.add_argument(--project, defaultROOT / runs/detect, helpsave results to project/name)parser.add_argument(--name, defaultexp, helpsave results to project/name)parser.add_argument(--exist-ok, actionstore_true, helpexisting project/name ok, do not increment)parser.add_argument(--line-thickness, default3, typeint, helpbounding box thickness (pixels))parser.add_argument(--hide-labels, defaultFalse, actionstore_true, helphide labels)parser.add_argument(--hide-conf, defaultFalse, actionstore_true, helphide confidences)parser.add_argument(--half, actionstore_true, helpuse FP16 half-precision inference)parser.add_argument(--dnn, actionstore_true, helpuse OpenCV DNN for ONNX inference)opt parser.parse_args()opt.imgsz * 2 if len(opt.imgsz) 1 else 1 # expandprint_args(FILE.stem, opt)return optdef main(opt):check_requirements(exclude(tensorboard, thop))run(**vars(opt))if __name__ __main__:opt parse_opt()main(opt)5. 实验效果
实验效果如下 工程源码下载链接https://github.com/up-up-up-up/yolov5_Monocular_measure
更多测距代码见博客主页