YoloV5源码注释解读(ultralytics版本)(detect.py)

近期在读源码,ultralytics版本应该是github上最热版本,其功能也非常强大,因此进行了注释学习。

下面是ultralytics的Yolov5的推理文件detect.py的注释解读,通过学习其实可以发现很多功能没有被注意到,可以对于项目有非常大的帮助。

简单总结,detect.py按照执行顺序进行解读:

第一部分:导入包(系统包或自定义包)
第二部分:程序入口,执行程序
第三部分:Yolov5参数设置(命令行传参解析参数或代码更改参数)
第四部分:执行main函数(检查环境,执行run函数)
第五部分:执行run函数(推理)(又分为5小节)

参考链接:Yolov5(ultralytics版本detect.py讲解)

该视频讲的很细,同时加上了一些自己的理解,整理如下。由于官网代码也在更新,因此可能有出入。

以下是整体代码注释版:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# 此部分为官网指导使用命令行进行推理的命令
"""
Run YOLOv5 detection inference on images, videos, directories, globs, YouTube, webcam, streams, etc.

Usage - sources:
    $ python detect.py --weights yolov5s.pt --source 0                               # webcam
                                                     img.jpg                         # image
                                                     vid.mp4                         # video
                                                     screen                          # screenshot
                                                     path/                           # directory
                                                     list.txt                        # list of images
                                                     list.streams                    # list of streams
                                                     'path/*.jpg'                    # glob
                                                     'https://youtu.be/Zgi9g1ksQHc'  # YouTube
                                                     'rtsp://example.com/media.mp4'  # RTSP, RTMP, HTTP stream

Usage - formats:
    $ python detect.py --weights yolov5s.pt                 # PyTorch
                                 yolov5s.torchscript        # TorchScript
                                 yolov5s.onnx               # ONNX Runtime or OpenCV DNN with --dnn
                                 yolov5s_openvino_model     # OpenVINO
                                 yolov5s.engine             # TensorRT
                                 yolov5s.mlmodel            # CoreML (macOS-only)
                                 yolov5s_saved_model        # TensorFlow SavedModel
                                 yolov5s.pb                 # TensorFlow GraphDef
                                 yolov5s.tflite             # TensorFlow Lite
                                 yolov5s_edgetpu.tflite     # TensorFlow Edge TPU
                                 yolov5s_paddle_model       # PaddlePaddle
"""
#-----------------------------------------------------------------------------------------------------------------------------#

# 第一部分:导包 #################################################################################################################
#-----------------------------------------------------------------------------------------------------------------------------#
import argparse                             # 解析命令行
import os                                   # 操作系统接口库
os.environ["GIT_PYTHON_REFRESH"] = "quiet"  # 为解决报错增加的
import platform                             # 系统环境存在win、linux、类unix情况,使用platform模块可以判断当前的系统环境
import sys                                  # sys模块是与python解释器交互的一个接口,sys模块提供了许多函数和变量来处理Python运行时环境的不同部分
from pathlib import Path                    # 面向对象的方式来与文件系统交互
import torch                                # torch包可以用来构建和训练神经网络,它是一个基于Python的科学计算库,支持GPU加速的张量计算和深度学习。

# 根路径设置,用于后续参数设置中
FILE = Path(__file__).resolve()                             # 获得当前文件绝对路径 D:\yolov5-master\yolov5-master\detect.py
ROOT = FILE.parents[0]  # YOLOv5 root directory             # 获得YOLOv5根目录路径 D:\yolov5-master\yolov5-master
if str(ROOT) not in sys.path:                               # 将YOLOv5路径加入到模块查询列表中
    sys.path.append(str(ROOT))
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # relative  # 转换成相对路径 ROOT = (D:\yolov5-master\yolov5-master)

# 加载自定义模块
# 这些模块均从该yolov5项目中不同文件夹中加载,从而实现不同作用

# DetectMultiBackend 不同深度学习框架选择
from models.common import DetectMultiBackend

# IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm'  # include image suffixes
# VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv'  # include video suffixes
# LoadImages:图片或视频加载; LoadScreenshots:屏幕加载; LoadStreams:网络流加载  # RTSP, RTMP, HTTP streams`
from utils.dataloaders import IMG_FORMATS, VID_FORMATS, LoadImages, LoadScreenshots, LoadStreams

# LOGGER:日志打印 Profile:时间处理 check_file:文件检查 check_img_size:图片尺寸检查 check_imshow:图像展示检查
# check_requirements:requirements.txt环境文件检查 colorstr:颜色检查 cv2:opencv库
# increment_path:路径增量  non_max_suppression:NMS print_args:信息打印 scale_boxes:检测框尺度调整
# strip_optimizer:优化器  xyxy2xywh:坐标转换 (xyxy) to (x_center,ycenter,width,height)
from utils.general import (LOGGER, Profile, check_file, check_img_size, check_imshow, check_requirements, colorstr, cv2,
                           increment_path, non_max_suppression, print_args, scale_boxes, strip_optimizer, xyxy2xywh)

# Annotator:绘图工具 colors:颜色实例 save_one_box:保存标记框
from utils.plots import Annotator, colors, save_one_box

# select_device:选择cpu or GPU  smart_inference_mode: torch装饰器
from utils.torch_utils import select_device, smart_inference_mode

# 第五部分:执行run ############################################################################################################
#-----------------------------------------------------------------------------------------------------------------------------
@smart_inference_mode()
# 初始化参数,若相应参数修改,则此部分相应参数会被覆盖
def run(
        weights=ROOT / 'yolov5s.pt',  # model path or triton URL           # 权重
        source=ROOT / 'data/images',  # file/dir/URL/glob/screen/0(webcam) # 推理源地址
        data=ROOT / 'data/coco128.yaml',  # dataset.yaml path              # 数据集yaml文件
        imgsz=(640, 640),  # inference size (height, width)                # 图片尺寸
        conf_thres=0.25,  # confidence threshold                           # 置信度参数,高于此参数将会保存于图片中
        iou_thres=0.45,  # NMS IOU threshold                               # IOU参数,高于此参数将会保存于图片中
        max_det=1000,  # maximum detections per image                      # 每张图片最大检测数
        device='',  # cuda device, i.e. 0 or 0,1,2,3 or cpu                # cup or GPU
        view_img=False,  # show results                                    # 展示结果
        save_txt=False,  # save results to *.txt                           # 保存检测框坐标txt文件
        save_conf=False,  # save confidences in --save-txt labels          # 保存置信度
        save_crop=False,  # save cropped prediction boxes                  # 检测框裁剪
        nosave=False,  # do not save images/videos                         # 是否保存检测框信息
        classes=None,  # filter by class: --class 0, or --class 0 2 3      # 是否进行特定目标的检测
        agnostic_nms=False,  # class-agnostic NMS                          # NMS去除不同类别之间的框
        augment=False,  # augmented inference                              # 图像增强,推理时候才TTA推理,官网有介绍
        visualize=False,  # visualize features                             # 可视化特征
        update=False,  # update all models                                 # 更新所有模型
        project=ROOT / 'runs/detect',  # save results to project/name      # 结果保存路径
        name='exp',  # save results to project/name                        # 结果具体保存路径
        exist_ok=False,  # existing project/name ok, do not increment      # 推理结果是否覆盖,不覆盖则exp,exp1,exp2递增
        line_thickness=3,  # bounding box thickness (pixels)               # 标记框线宽度
        hide_labels=False,  # hide labels                                  # 隐藏标签
        hide_conf=False,  # hide confidences                               # 隐藏置信度
        half=False,  # use FP16 half-precision inference                   # 是否采用半精度
        dnn=False,  # use OpenCV DNN for ONNX inference                    # 是否使用OpenCV DNN预测
        vid_stride=1,  # video frame-rate stride                           # 视频流推理步长
):

# 第五部分:执行run #############################################################################################################
# 第五部分第一小节   ------------------------------------------------------------------------------------------------------------
# 输入源判断(True or False),图片、视频(is_file)、网络流(is_url)、摄像头(webcam)、屏幕(screenshot);

    # 转换source为字符串
    source = str(source)

    # save inference images # 保存推理图片; 若nosave传入false,且source不是以txt结尾,save_img = True
    # endswith检查字符串是否以指定字符串结尾,是返回True,否则False
    save_img = not nosave and not source.endswith('.txt')

    # Path(pathlib模块)提取路径信息,若sourece = 'D:/data/image/a.jpg',Path(source) ='D:/data/image/a.jpg'
    # suffix(提取后缀),Path(source).suffix[1:] = jpg; Path(source).suffix[1] = j
    # 判断后缀名字是否在IMG_FORMATS + VID_FORMATS列表中,可通过ctrl查看
    # IMG_FORMATS = 'bmp', 'dng', 'jpeg', 'jpg', 'mpo', 'png', 'tif', 'tiff', 'webp', 'pfm'  # include image suffixes
    # VID_FORMATS = 'asf', 'avi', 'gif', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'ts', 'wmv'  # include video suffixes
    # 如果存在此目录中,则返回True,即is_file = True
    is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)

    # lower转小写,upper转化大写;将source信息转化为小写
    # startwith检查字符串是否以指定字符串开头,是返回True,否则False
    # 若以相应网络流开头,is_url = True
    is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))

    # isnumeric检测字符串是否只有数字组成
    # webcam通过三个或,判断是否是摄像头,若是,webcam = True
    webcam = source.isnumeric() or source.endswith('.streams') or (is_url and not is_file)

    # screenshot判断是否是当前屏幕
    # 若True,screenshot = True
    screenshot = source.lower().startswith('screen')

    # 若is_url和is_file同时成立,则通过check_file进行下载相应文件
    if is_url and is_file:
        source = check_file(source)  # download

# 第五部分        #############################################################################################################
# 第五部分第二小节   ------------------------------------------------------------------------------------------------------------
# save_dir:推理完成(带标记框)图片路径设置; save_dir/labels:开启保存标记信息的txt路径设置;

    # Directories
    # project,name从第三部分传参中获取
    # 增量文件或文件路径; i.e. runs/exp --> runs/exp{sep}2, runs/exp{sep}3, ... etc.
    save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)                  # increment run
    (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # make dir

# 第五部分        #############################################################################################################
# 第五部分第三小节   ------------------------------------------------------------------------------------------------------------
# 加载模型:cpu or GPU选择;深度学习框架选择;加载stride步长,names类别名,权重pt文件

    # Load model
    # 根据device参数,选择cpu或者GPU
    device = select_device(device)

    # DetectMultiBackend:判断不同深度学习框架:
    #   PyTorch:                        weights = *.pt
    #   TorchScript:                    *.torchscript
    #   ONNX Runtime:                   *.onnx
    #   ONNX OpenCV DNN:                *.onnx --dnn
    #   OpenVINO:                       *_openvino_model
    #   CoreML:                         *.mlmodel
    #   TensorRT:                       *.engine
    #   TensorFlow SavedModel:          *_saved_model
    #   TensorFlow GraphDef:            *.pb
    #   TensorFlow Lite:                *.tflite
    #   TensorFlow Edge TPU:            *_edgetpu.tflite
    #   PaddlePaddle:                   *_paddle_model
    # 传入weight(权重)、device = cup or GPU, dnn推理,data文件(yaml)、fp16半精度推理
    model = DetectMultiBackend(weights, device=device, dnn=dnn, data=data, fp16=half)

    # 模型步长,模型类别名,模型pt文件(PyTorch)
    # stride一般是32的倍数,names对应data/*.yaml中的names(类别),pt对应权重文件
    # yolov5n,yolov5s,yolov5m,yolov5l,yolov5x没有将会下载
    stride, names, pt = model.stride, model.names, model.pt

    # 检测图片尺寸(32倍数)
    imgsz = check_img_size(imgsz, s=stride)  # check image size

# 第五部分        #############################################################################################################
# 第五部分第四小节   ------------------------------------------------------------------------------------------------------------
# 加载模型:webcam or screenshot or source(根据布尔值进行调用各自函数加载)

    # Dataloader
    bs = 1  # batch_size 每次推理一张图片

    # webcam是否True(摄像头检测)
    if webcam:
        view_img = check_imshow(warn=True)
        dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)
        bs = len(dataset)

    # screenshot是否True(屏幕检测)
    elif screenshot:
        dataset = LoadScreenshots(source, img_size=imgsz, stride=stride, auto=pt)

    # LoadImages:加载图片文件
    # 传入source,imasz,stride,pt,vid_stride
    # 在LoadImages,主要是对source进行操作,若是文件夹,则会遍历文件夹中所有图片存入dataset中
    else:
        dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt, vid_stride=vid_stride)

    # vid_path,vid_writer = [None][None]
    # vid_path保存视频的路径,vid_writer;
    vid_path, vid_writer = [None] * bs, [None] * bs

# 第五部分        #############################################################################################################
# 第五部分第五小节   ------------------------------------------------------------------------------------------------------------
# 推理

    # Run inference
    # warmup,通过运行一次warmup来预热模型
    model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *imgsz))  # warmup

    # seen = 0(计数,后续通过+1,处理多少图片)
    # windows空列表,用于后续处理显示图片
    # dt:耗时记录
    seen, windows, dt = 0, [], (Profile(), Profile(), Profile())

    # dataset通过LoadImages加载而来
    # LoadImages中存储了path(路径信息), im(经尺寸处理后的图片), im0(原图),vid_cap(视频参数),s是打印信息
    for path, im, im0s, vid_cap, s in dataset:
        
        with dt[0]:

            # torch.from_numpy转换成torch支持的格式,放入模型device中
            im = torch.from_numpy(im).to(model.device)

            # 判断是否版精度
            im = im.half() if model.fp16 else im.float()  # uint8 to fp16/32

            # 图片所有像素点归一化(简化计算,否则电脑受不了)
            im /= 255  # 0 - 255 to 0.0 - 1.0
            if len(im.shape) == 3:
                im = im[None]  # expand for batch dim 为batch扩充维度;(1,3,640,480)

        # Inference
        # 推理阶段,得到所有检测框pred信息 torch.size=[1,18900,85]
        # 以data/images输入的第一张bus.jpg为例子
        # 经上面处理图片是(1,3,640,480),经过8倍,16倍,32倍下采样
        # 从三个层级划分网格(可查yolov5网络结构),每个网格又预测3个检测框,(80*60+40*30+20*15)*3=18900
        # 85 = [x,y,w,h,置信度,coco80个类别]
        with dt[1]:
            visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
            pred = model(im, augment=augment, visualize=visualize)

        # NMS
        # 非极大值抑制
        # pred返回;最终保留了5个检测框,每个检测框包含6个信息:[xmin,ymin,xmax,ymax,置信度p,类别c]
        with dt[2]:
            pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)

        # Second-stage classifier (optional)
        # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)

        # Process predictions
        # i是每个batch的信息,处理到第几个物体
        # det代表每个检测框的信息,在这张图片中有5个检测框,且有6个信息[5,6]=[xmin,ymin,xmax,ymax,置信度p,类别c]
        for i, det in enumerate(pred):  # per image
            seen += 1 # 计数,来遍历所有图片

            # webcam = True
            if webcam:  # batch_size >= 1
                p, im0, frame = path[i], im0s[i].copy(), dataset.count
                s += f'{i}: '
            else:
                # p路径,im0原图,frame视频流的图片
                p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
            p = Path(p)  # to Path

            # 检测图片存储路径
            save_path = str(save_dir / p.name)  # im.jpg

            # 坐标txt存储路径
            txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}')  # im.txt

            # s图片尺寸信息
            s += '%gx%g ' % im.shape[2:]  # print string

            # 原图片宽和高信息
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh

            # 当裁剪参数为真,将进行检测框裁剪为imc
            imc = im0.copy() if save_crop else im0  # for save_crop

            # Annotator绘图工具(原图,线条尺寸,类别名)
            annotator = Annotator(im0, line_width=line_thickness, example=str(names))

            # 通过判断det长度不为0,来开始画框
            if len(det):

                # Rescale boxes from img_size to im0 size
                # scale_boxes坐标映射,将检测框缩放回原图比例
                det[:, :4] = scale_boxes(im.shape[2:], det[:, :4], im0.shape).round()

                # Print results
                # 打印结果
                for c in det[:, 5].unique():
                    n = (det[:, 5] == c).sum()  # detections per class
                    s += f"{n} {names[int(c)]}{'s' * (n > 1)}, "  # add to string

                # Write results
                # 保存预测结果,图片,txt,裁剪信息
                for *xyxy, conf, cls in reversed(det):
                    if save_txt:  # Write to file
                        # 将xyxy格式转为xywh(中心点+宽高)格式,并归一化,转化为列表再保存
                        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
                        # line的形式是:save_conf为true,则line的形式是:类别 x_center y_center weight height 置信度
                        line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
                        # 写入对应txt文件夹
                        with open(f'{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 image
                        c = int(cls)  # integer class 类别
                        label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
                        annotator.box_label(xyxy, label, color=colors(c, True)) # 绘制边框
                    # 在原图上画框,剪裁保存,保存在save_dir/crops下(单独保存)
                    if save_crop:
                        save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)

            # Stream results
            # im0 = 画好框的图片
            im0 = annotator.result()

            # viwe_img为True,显示图片
            if view_img:
                if platform.system() == 'Linux' and p not in windows:
                    windows.append(p)
                    cv2.namedWindow(str(p), cv2.WINDOW_NORMAL | cv2.WINDOW_KEEPRATIO)  # allow window resize (Linux)
                    cv2.resizeWindow(str(p), im0.shape[1], im0.shape[0])
                cv2.imshow(str(p), im0)
                cv2.waitKey(1)  # 1 millisecond 暂停1秒

            # 保存相应结果
            # Save results (image with detections)
            if save_img:
                # 保存图片文件
                if dataset.mode == 'image':
                    cv2.imwrite(save_path, im0)
                # 保存视频或流文件
                else:  # 'video' or 'stream'
                    if vid_path[i] != save_path:  # new video
                        vid_path[i] = save_path
                        if isinstance(vid_writer[i], cv2.VideoWriter):
                            vid_writer[i].release()  # release previous video writer
                        if vid_cap:  # video
                            fps = vid_cap.get(cv2.CAP_PROP_FPS)             # 视频帧速率 FPS
                            w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 获取视频帧宽度
                            h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频帧高度
                        else:  # stream
                            fps, w, h = 30, im0.shape[1], im0.shape[0]
                        save_path = str(Path(save_path).with_suffix('.mp4'))  # force *.mp4 suffix on results videos
                        vid_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}{'' if len(det) else '(no detections), '}{dt[1].dt * 1E3:.1f}ms")

    # Print results
    # 打印结果信息
    t = tuple(x.t / seen * 1E3 for x in dt)  # speeds per image 推理每张图片耗时
    LOGGER.info(f'Speed: %.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(f"Results saved to {colorstr('bold', save_dir)}{s}")
    if update:
        strip_optimizer(weights[0])  # update model (to fix SourceChangeWarning)


# 第三部分:parse_opt传参数 ##################################################################################################
# --------------------------------------------------------------------------------------------------------------------------
def parse_opt():
    parser = argparse.ArgumentParser()
    # 权重文件,Yolov5有五个默认权重文件,按照权重模型的小到大分别为yolov5n,yolov5s,yolov5m,yolov5l,yolov5x,精度逐渐增加,同时由于模型增大,相应推理时间会增大
    parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model path or triton URL')
    # 推理源地址,可以是单张图片,文件夹,摄像头地址等,详见最上面关于官方推理说明
    parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob/screen/0(webcam)')
    # 数据集的yaml文件,不同数据集,相应的yaml文件也不同
    parser.add_argument('--data', type=str, default=ROOT / 'data/coco.yaml', help='(optional) dataset.yaml path')
    # 推理图片大小,32倍数
    parser.add_argument('--imgsz', '--img', '--img-size', nargs='+', type=int, default=[640], help='inference size h,w')
    # 置信度参数
    parser.add_argument('--conf-thres', type=float, default=0.25, help='confidence threshold')
    # iou参数
    parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
    # 每张图片最大检测框,1000个标记框出来
    parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
    # 默认cpu计算,如果设置参数0,1,2,3等将启用GPU,0,1,2,3为电脑GPU显卡编号,同理,若想使用GPU需要配置GPU环境
    parser.add_argument('--device', default='', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    # 是否可视化结果,store_true为动作,只有传入时才会触发此条件,如命令python detect.py --save-txt
    # 当然,也可以改为store_false,这样运行此参数就为真    # 下面的store_true原理相同
    parser.add_argument('--view-img', action='store_true', help='show results')
    # 是否保存检测框的坐标信息,以yolo格式的txt形式保存
    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('--save-crop', action='store_true', help='save cropped prediction boxes')
    # 是否保存含有框标记的图片文件
    parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
    # 通过设置参数0,1,2等等,只进行某一类或者某几类的识别任务,如0在coco数据集中代表person,如设置成0,则将只识别人
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
    # 在执行目标检测任务时,可能对同一个目标进行多次检测,NMS是确保算法对每个对象得到一个检测框的方法,具体如何是实现可以去搜索对应的文章
    parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
    # 是否使用使用数据增强的方式进行推理,官网指导为TTA
    parser.add_argument('--augment', action='store_true', help='augmented inference')
    # 可视化特征图
    parser.add_argument('--visualize', action='store_true', help='visualize features')
    # 如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False
    parser.add_argument('--update', action='store_true', help='update all models')
    # 推理文件存储路径
    parser.add_argument('--project', default=ROOT / 'runs/detect', help='save results to project/name')
    # 具体的存储文件夹路径,增量方式,exp,exp1...
    parser.add_argument('--name', default='exp', help='save results to project/name')
    # 模型输出是否保存在已有的文件夹下,如果设置该参数,每次运行的结果都会存储在原有的文件夹下
    parser.add_argument('--exist-ok', action='store_true', help='existing project/name ok, do not increment')
    # 检测框线条的粗细
    parser.add_argument('--line-thickness', default=3, type=int, help='bounding box thickness (pixels)')
    # 是否隐藏检测结果的标签
    parser.add_argument('--hide-labels', default=False, action='store_true', help='hide labels')
    # 是否隐藏置信度
    parser.add_argument('--hide-conf', default=False, action='store_true', help='hide confidences')
    #  该参数是是否使用FP16半精度推理;
    #  在训练阶段,梯度更新往往是很微小的,需要相对较高的精度,一般要用FP32以上;
    #  在预测时,精度要求没有那么高,一般F16(半精度)就可以,甚至可以用INT8,精度影响不会很大;同时低精度的模型占用空间更小。有利于部署在嵌入式模型里面
    parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
    # dnn;使用使用OpenCV DNN进行ONNX推理
    parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
    # 视频流的步长
    parser.add_argument('--vid-stride', type=int, default=1, help='video frame-rate stride')
    opt = parser.parse_args()
    opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1  # expand 判断图片尺寸的变量长度是否是2,最终将转化为[640,640]
    print_args(vars(opt))   # 打印所有opt中参数信息
    return opt              # opt存储了所有变量信息

# 第四部分:执行main(opt),检查环境,执行run函数 #################################################################################
# --------------------------------------------------------------------------------------------------------------------------
def main(opt):
    check_requirements(exclude=('tensorboard', 'thop')) # 调用check_requirements,根据requirements.txt检查环境依赖
    # 运行run函数
    # 一个星( * ):表示接收的参数作为元组来处理
    # 两个星( ** ):表示接收的参数作为字典来处理
    # 将opt变量的属性和属性值作为关键字参数传递给run()函数。
    run(**vars(opt))

# 第二部分:程序入口 #############################################################################################################
# -----------------------------------------------------------------------------------------------------------------------------
if __name__ == '__main__':
    opt = parse_opt()   # 实例化parse_opt函数,将其参数赋予opt
    main(opt)           # 将opt送入main函数中,调用main()

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: yolov5中的test.pydetect.py是两个Python脚本,用于在训练好的模型上进行目标检测。 test.py主要用于测试模型的性能,可以通过设置不同的参数来测试不同的模型,例如模型的大小、批量大小、数据集等。它会输出模型的精度、召回率和F1分数等指标,以及检测结果的可视化图像。 detect.py则是用于实际的目标检测应用,它可以读取图像或视频文件,并在其中检测出目标物体。它也可以设置不同的参数,例如置信度阈值、非极大值抑制等,以控制检测结果的准确性和速度。它会输出检测结果的可视化图像,并可以将结果保存到文件中。 ### 回答2: YOLOv5是一种高效的目标检测算法,它可以在高分辨率下快速、准确地检测多个物体。在YOLOv5中,test.pydetect.py是两个非常重要的文件,下面我就分别对它们进行介绍: 一、test.py test.pyYOLOv5中的一个重要文件,它主要用于在给定的权重下测试模型的精度。 在使用test.py时,需要指定检测的图片或视频路径,还需要输入模型权重路径。同时还可以设置一些参数,例如置信度阈值和非极大值抑制阈值等。test.py还提供了一些可视化的选项,例如显示结果框、预测框、类别等。 使用test.py可以对训练好的模型进行测试,检查它的准确度和可靠性,有助于我们更好地选择和调整模型。 二、detect.py detect.pyYOLOv5中的另一个重要文件,它主要用于在给定的权重下检测图像或视频中的对象。 在使用detect.py时,需要指定待检测文件的路径和需要使用的权重文件。和test.py一样,还可以设置一些参数,例如置信度阈值和非极大值抑制阈值等。不同的是,detect.py可以支持实时摄像头检测,也可以保存检测结果为视频或图片。 detect.pyYOLOv5中非常重要的一个文件,它可以快速、准确地检测出图像或视频中的目标,为后续的处理提供了很大的帮助。 总结: test.pydetect.pyYOLOv5中非常重要的文件,它们分别用于模型测试和目标检测。使用它们可以检查模型的精度和可靠性,也可以实现快速、准确地目标检测。这两个文件的使用非常灵活,可以根据具体的应用场景灵活选择和调整参数。 ### 回答3: yolov5是一种目标检测算法,它的最新版本yolov5s。其中,yolov5中的test.pydetect.py是两个重要的脚本文件,下面我将分别进行介绍。 1. test.py test.pyyolov5中用于测试的脚本文件。它主要用于将训练得到的模型应用于测试集或者用户上传的图像上,进行目标检测以及预测。该脚本具有较高的灵活性,可以通过命令行设置多个参数,以满足不同情况下的需求。 test.py主要的参数包括: - weights:该参数用于指定模型的权重路径 - source:该参数用于指定待测试的图像源,可以是单张图片、视频文件或者相机输入 - img-size:该参数用于指定输入图像的大小 - conf-thres:该参数用于指定置信度阈值 - iou-thres:该参数用于指定IoU(交并比)阈值 通过运行test.py脚本,我们可以很方便地对模型进行测试,获得目标检测的结果。 2. detect.py detect.pyyolov5中用于检测的脚本文件。它主要用于对单张图片进行目标检测,是test.py的一种特化形式。detect.py的参数设置与test.py类似,也是通过命令行设置。 detect.py主要的参数包括: - weights:该参数用于指定模型的权重路径 - img:该参数用于指定待检测的图像路径 - conf:该参数用于指定置信度阈值 - iou:该参数用于指定IoU阈值 - classes:该参数用于指定待检测的目标类别 使用detect.py脚本可以很方便地对单张图片进行目标检测,给出目标框以及类别信息。 综上所述,test.pydetect.pyyolov5中非常重要的两个脚本文件,它们分别用于测试和检测,具有很高的灵活性和有效性,为yolov5的应用提供了很大的便利性和可靠性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值