吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 4994|回复: 15
收起左侧

[Python 转载] yolov5总结逐行读一遍代码detect.py

   关闭 [复制链接]
hzsd 发表于 2022-7-16 11:48
[Python] 纯文本查看 复制代码
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
"""
Run inference on images, videos, directories, streams, etc.

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

import argparse
import os
import sys
from pathlib import Path

import cv2  # opencv包
import torch
import torch.backends.cudnn as cudnn
# 第一部分导入已经安装在环境里的库

FILE = Path(__file__).resolve()  # __file__获取当前文件的绝对路径‪E:\YOLOTOW\detect.py
ROOT = FILE.parents[0]  # YOLOv5 root directory 获取ROOT的次一级目录比如‪ E:\YOLOTOW父目录

if str(ROOT) not in sys.path:   # 模块查询的路径列表(确保导包的文件路径存在路径中)
    sys.path.append(str(ROOT))  # add ROOT to PATH
ROOT = Path(os.path.relpath(ROOT, Path.cwd()))  # 绝对路径转化为相对路径
# 第二部分就是处理文件的路径问题

from 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
# 第三部分导入文件里的类
# 导入py包

@torch.no_grad()
# 核心的run函数的部分
# 分成6个部分
# run(函数传入的值,设置了实参,如果没有传入则默认使用实参的内容)
def run(weights=ROOT / 'yolov5s.pt',  # 指定不同的权重文件
        source=ROOT / 'data/images',  # 指定读取那个文件夹文件或者视频亦或者直播流地址
        imgsz=640,  # 模型在检测图片前会把图片resize成640的size,然后再喂进网络里,并不是说会把们最终得到的结果resize成640大小
        conf_thres=0.25,  # 置信度的阈值
        iou_thres=0.45,  # 调节IoU的阈值
        max_det=1000,  # 最大检测数量,默认是最多检测1000个目标
        device='',  # GPU数量,如果不指定的话,他会自动检测,这个参数是给GPU多的土豪准备的
        view_img=False,  # 检测的时候是否实时的把检测结果显示出来
        save_txt=False,  # 是否把检测结果保存成一个.txt的格式
        save_conf=False,  # 是否以.txt的格式保存目标的置信度
        save_crop=False,  # 是否把模型检测的物体裁剪下来---就是实时保存检测到的目标
        nosave=False,  # 不保存预测的结果,但是还会生成exp文件夹,只不过是一个空的exp
        classes=None,  # 可以给变量指定多个赋值,也就是说我们可以把“0”赋值给“classes”,也可以把“0”“2”“4”“6”都赋值给“classes  暂时理解为指定是被模型的类型
        agnostic_nms=False,  # 增强版的nms,算是一种trick吧
        augment=False,  # 这个参数也是一种增强的方式
        visualize=False,  # 是否把特征图可视化出来,如果开启了这和参数可以看到exp文件夹下又多了一些文件,这里.npy格式的文件就是保存的模型文件,可以使用numpy读写,.png就是图片文件啦
        update=False,  # 指定这个参数,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息
        project=ROOT / 'runs/detect',  # 预测结果保存的路径
        name='exp',  # 预测结果保存的文件夹名字
        exist_ok=False,  # 每次预测模型的结果是否保存在原来的文件夹,如果指定了这个参数的话,那么本次预测的结果还是保存在上一次保存的文件夹里;如果不指定就是每次预测结果保存一个新的文件夹下
        line_thickness=3,  # 这个参数就是调节预测框线条粗细的,因为有的时候目标重叠太多会产生遮挡
        hide_labels=False,  # 参数就是隐藏标签的
        hide_conf=False,  # 隐藏标签的置信度用的
        half=False,  # 是否使用 FP16 半精度推理,简单介绍一下低精度技术
        dnn=False,  # 这个参数的意思就是是否使用 OpenCV DNN 进行 ONNX 推理 DNN即Deep Neural Networks
        ):
    # 输入的路径变为字符串
    source = str(source)  # 第一部分对source  就是命令行传入的部分进行了一些判断--source  data/images/fishman.jpg
    # 处于预测路径 str() 强制把路径转化为字符串类型
    # 是否保存图片和txt文件
    save_img = not nosave and not source.endswith('.txt')  # nosave=False因为默认值是false所以not  一般表示取反  以及判断文件后缀是否为txt然后取反true表示预测结果需要保存下来
    # 判断文件是否是视频流
    # Path()提取文件名 例如:Path("./data/test_images/bus.jpg") Path.name->bus.jpg Path.parent->./data/test_images Path.suffix->.jpg
    is_file = Path(source).suffix[1:] in (IMG_FORMATS + VID_FORMATS)  # 判断文件路径是否为视频以及图片格式 提取文件后缀名是否符合要求的文件,例如:是否格式是jpg, png, asf, avi等
    # .lower()转化成小写 .upper()转化成大写 .title()首字符转化成大写,其余为小写, .startswith('http://')返回True or Flase 
    is_url = source.lower().startswith(('rtsp://', 'rtmp://', 'http://', 'https://'))  # 判断文件路径是否为直播格式网络流地址
    # .isnumeric()是否是由数字组成,返回True or False
    webcam = source.isnumeric() or source.endswith('.txt') or (is_url and not is_file) # 判断是否为启动电脑摄像头0数字为 0 或者文件为txt或者为直播流格式等等说
    # source.isnumeric()数字为0,则表示为打开电脑的第一个摄像头   source.endswith('.txt') 表示传入的路径是否为txt结尾的  (is_url and not is_file)表示是否为直播流开头或者已图片或者视频开头的  not is_file 表示不是文件
    if is_url and is_file:
        # 判断 is_url 是否为ture  和 is_file 是否为true 也就是是否为直播流和视频文件
        # 返回文件
        source = check_file(source)  # 如果是true的,他就会根据直播流的地址去下载视频----专门处理直播流参数的

    # 第二部分新建了一个保存结果的文件夹
    # 预测路径是否存在,不存在新建,按照实验文件以此递增新建
    save_dir = increment_path(Path(project) / name, exist_ok=exist_ok)  # project表示  project=ROOT / 'runs/detect', 这个文件部分 name对于的是   name='exp',这个参数
    # increment_path表示增量路径  检测文件夹下的exp数字到几了,然后再加一一个文件夹  也就表示save_dir  文件下的这个路径
    (save_dir / 'labels' if save_txt else save_dir).mkdir(parents=True, exist_ok=True)  # 判断save_txt是否为ture 如果是则增量路径创建文件夹用来去存储一个结果

    # 第三部分加载模型的权重
    # 获取设备 CPU/CUDA
    device = select_device(device)  # 根据加载环境不同去选择加载的设备
    # 检测编译框架PYTORCH/TENSORFLOW/TENSORRT
    model = DetectMultiBackend(weights, device=device, dnn=dnn)  # 选择模型的后端框架DetectMultiBackend weights表示ROOT / 'yolov5s.pt' device表示cpu或者gpu  dnn表示 dnn=False,
    stride, names, pt, jit, onnx = model.stride, model.names, model.pt, model.jit, model.onnx  # 加载完成之后,开始检测出模型的步长 模型的昵称 等参数
    # 确保输入图片的尺寸imgsz能整除stride=32 如果不能则调整为能被整除并返回
    imgsz = check_img_size(imgsz, s=stride)  # imgsz表示输入的模型的图片的大小  stride表示模型的步长 然后检测是否为模型的倍数 如果是那么还是640*640的尺寸  必须是输入尺寸的32倍一定是倍数关系,如果没有则会默认给你计算一个倍数

    # Half
    # 如果不是CPU,使用半进度(图片半精度/模型半精度)
    half &= pt and device.type != 'cpu'  # half precision only supported by PyTorch on CUDA
    if pt:
        model.model.half() if half else model.model.float()

    # 第四部分专门定义了 Dataloader模块,用来加载待预测的图片
    # 使用视频流或者页面
    if webcam:
        # 判断webcam是否是数字也就是是否是调用到电脑摄像头
        view_img = check_imshow()
        cudnn.benchmark = True  # set True to speed up constant image size inference
        dataset = LoadStreams(source, img_size=imgsz, stride=stride, auto=pt and not jit)
        bs = len(dataset)  # batch_size
    else:
        # 如果不是则会跑到这里来,加载图片文件
        # 直接从source文件下读取图片
        dataset = LoadImages(source, img_size=imgsz, stride=stride, auto=pt and not jit)
        # 加载图片文件是先是初始化LoadImages(专门加载图片的模块)对象
        bs = 1  # batch_size  表示每次输入一张图片
    # 保存的路径
    vid_path, vid_writer = [None] * bs, [None] * bs  # 设置列表长度 默认为1

    # 第五部分去执行一个模型的推理过程--把图片输入模型产生一个预测结果,并把预测框给画出来
    if pt and device.type != 'cpu':
        model(torch.zeros(1, 3, *imgsz).to(device).type_as(next(model.model.parameters())))  # warmup 热身的意思 初始化先给一张空白的图片给gpu跑一下预热,机器启动
    dt, seen = [0.0, 0.0, 0.0], 0  # 在识别前预设的用于存储一些结果信息 dt变量用来储存时间
    for path, im, im0s, vid_cap, s in dataset:
        # 热身完成之后,就把图片依次传入模型,进行识别
        # dataset使用数据加载模型,进行一张一张的遍历识别
        # path 图片路径
        # im 预处理过的图片文件(RGB,长,宽)
        # im0s 表示原图
        # vid_cap 返回空
        # s 代表图片打印的信息
        t1 = time_sync()  # 代表时间与电脑系统时间同步
        # 转化到GPU上
        im = torch.from_numpy(im).to(device)  # im代表处理过的图片   也就是torch.Size([3,640,480]) 颜色通道 高 宽 转化格式之后再放到cpu/gpu上进行检测
        # 是否使用半精度
        im = im.half() if half else im.float()  # uint8 to fp16/32 判断你的模型有没有使用半精度
        im /= 255  # 0 - 255 to 0.0 - 1.0 把输入的图片数据除于255的大小,做了一个归一化的操作
        if len(im.shape) == 3:  # 判断输入图片的字符串尺寸是否为3 ([3,640,480]这个部分),
            # 增加一个维度
            im = im[None]  # expand for batch dim  然后扩增尺寸 torch.Size([1,3,640,480])
        t2 = time_sync()  # 代表时间与电脑系统时间同步
        dt[0] += t2 - t1  # 记录一下第1部分的耗时对应  dt变量用来储存时间


        # Inference
        # 第二部分就是对第一部分整理好的数据图片进行预测
        # 可是化文件路径
        visualize = increment_path(save_dir / Path(path).stem, mkdir=True) if visualize else False
         """
        pred.shape=(1, num_boxes, 5+num_class)
        h,w为传入网络图片的长和宽,注意dataset在检测时使用了矩形推理,所以这里h不一定等于w
        num_boxes = h/32 * w/32 + h/16 * w/16 + h/8 * w/8
        pred[..., 0:4]为预测框坐标=预测框坐标为xywh(中心点+宽长)格式
        pred[..., 4]为objectness置信度
        pred[..., 5:-1]为分类结果
        """

        #  visualize=False,  # 是否把特征图可视化出来,如果开启了这和参数可以看到exp文件夹下又多了一些文件,这里.npy格式判断这个
        # 保存特征图片
        pred = model(im, augment=augment, visualize=visualize)  # augment表示是否需要做一个数据增强  有点提升准确率代价就是速度被降低
        # pred变量的意思及是被检测出来的所有的数据的框--还需要再过滤一遍
        t3 = time_sync()  # 代表时间与电脑系统时间同步
        dt[1] += t3 - t2  # 记录一下第2部分的耗时对应  dt变量用来储存时间
        # 首先对每一张图片做了预处理


        # 再做一个NMS  也就是做一个非极大值的过滤
        # NMS   已经获取了所有的图片的信息
         """
        pred: 网络的输出结果
        conf_thres:置信度阈值
        ou_thres:iou阈值
        classes: 是否只保留特定的类别
        agnostic_nms: 进行nms是否也去除不同类别之间的框
        max-det: 保留的最大检测框数量
        ---NMS, 预测框格式: xywh(中心点+长宽)-->xyxy(左上角右下角)
        pred是一个列表list[torch.tensor], 长度为batch_size
        每一个torch.tensor的shape为(num_boxes, 6), 内容为box + conf + cls
        """
        pred = non_max_suppression(pred, conf_thres, iou_thres, classes, agnostic_nms, max_det=max_det)
        #  根据图片的conf_thres  iou_thres  置信度进行过滤置信度太低的就算了--根据置信度过滤
        #  max_det表示一张图片中能检测多少张图片默认值为1000个--超过一千个就会自动过滤剩下的目标
        # 预测+NMS的时间
        dt[2] += time_sync() - t3  # 记录一下第3部分的耗时对应  dt变量用来储存时间
        # Second-stage classifier (optional)
        # pred = utils.general.apply_classifier(pred, classifier_model, im, im0s)

        # Process predictions
        # 对所检测的框进行进一步处理
        # 最后把所有的检测框划到原图中--以及保存结果的操作
        for i, det in enumerate(pred):  # per image  遍历每一张图片  det代表那些检测框的信息
            seen += 1  # 也就是之前定义好的变量 计数的功能
            # mask for certain region
    
            if webcam:  # batch_size >= 1 判断是否是调用计算机的摄像头数
                p, im0, frame = path[i], im0s[i].copy(), dataset.count
                s += f'{i}: '
            else:
                p, im0, frame = path, im0s.copy(), getattr(dataset, 'frame', 0)
                #  p 表示循环图片的路径
                # frame 表示dataset有没有 frame的属性  如果没有则表示 0

            p = Path(p)  # to Path
            save_path = str(save_dir / p.name)  # im.jpg表示图片的保存路径
            txt_path = str(save_dir / 'labels' / p.stem) + ('' if dataset.mode == 'image' else f'_{frame}')  # im.txt 保存txt文件的路径
            s += '%gx%g ' % im.shape[2:]  # print string 拼接表示%gx%g图片的尺寸
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh  获得原图的宽和高的大小
            imc = im0.copy() if save_crop else im0  # for save_crop 判断是否需要把检测到的目标模型给裁剪下来
            annotator = Annotator(im0, line_width=line_thickness, example=str(names))  # 定义一个绘图的工具,传入原图与画线的工具,检测框的粗细  names  写上标签的标签名
            if len(det):
                # Rescale boxes from img_size to im0 size 因为尺寸问题预测出来的值不能直接画到原图中  做一个坐标映射的功能
                det[:, :4] = scale_coords(im.shape[2:], det[:, :4], im0.shape).round()

                # Print results  统计所有框的类别再添加到s的变量上 并打印出来
                for c in det[:, -1].unique():
                    n = (det[:, -1] == c).sum()  # detections per class
                    s += f"{n} {names[int(c)]}{'s' * (n > 1)}, "  # add to string

                # Write results  是否保存预测结果
                for *xyxy, conf, cls in reversed(det):
                    if save_txt:  # Write to file  如果需要保存成txt文档
                        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
                        line = (cls, *xywh, conf) if save_conf else (cls, *xywh)  # label format
                        with 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 image
                        c = int(cls)  # integer class 如果需要把图片保存则执行这里的内容 默认都是不执行的需要自己调
                        # c 变量获取cls变量的类别
                        label = None if hide_labels else (names[c] if hide_conf else f'{names[c]} {conf:.2f}')
                        # hide_labels 隐藏标签做一个判断,如果是则执行  再判断 是否隐藏标签的置信度
                        annotator.box_label(xyxy, label, color=colors(c, True))
                        if save_crop:
                            # 判断是否保存截图下来的目标框
                            save_one_box(xyxy, imc, file=save_dir / 'crops' / names[c] / f'{p.stem}.jpg', BGR=True)

            # Print time (inference-only) 每次遍历之后的打印的结果
            LOGGER.info(f'{s}Done. ({t3 - t2:.3f}s)')

            # Stream results
            im0 = annotator.result()  # 返回画好的图片
            if view_img:
                # 判断是否需要显示出来
                cv2.imshow(str(p), im0)
                cv2.waitKey(1)  # 1 millisecond

            # Save results (image with detections)
            if save_img:
                if dataset.mode == 'image':
                    cv2.imwrite(save_path, im0)
                    #  如果需要保存下来,则使用opencv保存图片的函数
                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)
                            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 += '.mp4'
                        vid_writer[i] = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*'mp4v'), fps, (w, h))
                    vid_writer[i].write(im0)

    # Print results 第六部分负责最终打印出来的结果输出信息
    t = tuple(x / seen * 1E3 for x in dt)  # speeds per image  统计打印结果
    LOGGER.info(f'Speed: %.1fms pre-process, %.1fms inference, %.1fms 结果可以写中文 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}")
        # 如果保存txt结果或者图片结果,则会而外打印出一些信息  说明一些图片被保存在那些的文件夹中
    if update:
        strip_optimizer(weights)  # update model (to fix SourceChangeWarning)


# 解析命令行传来的参数
# 这个部分代码可以分成三个部分
def parse_opt():
    """
        weights: 训练的权重路径,可以使用自己训练的权重,也可以使用官网提供的权重
        默认官网的权重yolov5s.pt(yolov5n.pt/yolov5s.pt/yolov5m.pt/yolov5l.pt/yolov5x.pt/区别在于网络的宽度和深度以此增加)
        source: 测试数据,可以是图片/视频路径,也可以是'0'(电脑自带摄像头),也可以是rtsp等视频流, 默认data/images
        data: 配置数据文件路径, 包括image/label/classes等信息, 训练自己的文件, 需要作相应更改, 可以不用管
        如果设置了只显示个别类别即使用了--classes = 0 或二者1, 2, 3等, 则需要设置该文件,数字和类别相对应才能只检测某一个类
        imgsz: 网络输入图片大小, 默认的大小是640
        conf-thres: 置信度阈值, 默认为0.25
        iou-thres:  做nms的iou阈值, 默认为0.45
        max-det: 保留的最大检测框数量, 每张图片中检测目标的个数最多为1000类
        device: 设置设备CPU/CUDA, 可以不用设置
        view-img: 是否展示预测之后的图片/视频, 默认False, --view-img 电脑界面出现图片或者视频检测结果
        save-txt: 是否将预测的框坐标以txt文件形式保存, 默认False, 使用--save-txt 在路径runs/detect/exp*/labels/*.txt下生成每张图片预测的txt文件
        save-conf: 是否将置信度conf也保存到txt中, 默认False
        save-crop: 是否保存裁剪预测框图片, 默认为False, 使用--save-crop 在runs/detect/exp*/crop/剪切类别文件夹/ 路径下会保存每个接下来的目标
        nosave: 不保存图片、视频, 要保存图片,不设置--nosave 在runs/detect/exp*/会出现预测的结果
        classes: 设置只保留某一部分类别, 形如0或者0 2 3, 使用--classes = n, 则在路径runs/detect/exp*/下保存的图片为n所对应的类别, 此时需要设置data
        agnostic-nms: 进行NMS去除不同类别之间的框, 默认False
        augment: TTA测试时增强/多尺度预测
        visualize: 是否可视化网络层输出特征
        update: 如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False
        project:保存测试日志的文件夹路径
        name:保存测试日志文件夹的名字, 所以最终是保存在project/name中
        exist_ok: 是否重新创建日志文件, False时重新创建文件
        line-thickness: 画框的线条粗细
        hide-labels: 可视化时隐藏预测类别
        hide-conf: 可视化时隐藏置信度
        half: 是否使用F16精度推理, 半进度提高检测速度
        dnn: 用OpenCV DNN预测
        """
    parser = argparse.ArgumentParser()
    parser.add_argument('--weights', nargs='+', type=str, default=ROOT / 'yolov5s.pt', help='model path(s)')
    parser.add_argument('--source', type=str, default=ROOT / 'data/images', help='file/dir/URL/glob, 0 for webcam')
    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.5, help='confidence threshold')
    parser.add_argument('--iou-thres', type=float, default=0.45, help='NMS IoU threshold')
    parser.add_argument('--max-det', type=int, default=1000, help='maximum detections per image')
    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='show 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('--save-crop', action='store_true', help='save cropped prediction boxes')
    parser.add_argument('--nosave', action='store_true', help='do not save images/videos')
    parser.add_argument('--classes', nargs='+', type=int, help='filter by class: --classes 0, or --classes 0 2 3')
    parser.add_argument('--agnostic-nms', action='store_true', help='class-agnostic NMS')
    parser.add_argument('--augment', action='store_true', help='augmented inference')
    parser.add_argument('--visualize', action='store_true', help='visualize features')
    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')
    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')
    parser.add_argument('--half', action='store_true', help='use FP16 half-precision inference')
    parser.add_argument('--dnn', action='store_true', help='use OpenCV DNN for ONNX inference')
    opt = parser.parse_args()
    # 以上部分定义一些命令行可以传来的参数 default表示一个默认值
    opt.imgsz *= 2 if len(opt.imgsz) == 1 else 1  # 对imgsz图片尺寸做了一个额外的判断  扩充维度, 如果是一位就扩充一位
    # 判断 imgaesz的长度是否为1,则需要把这个长度文字乘2 这样就保证长宽都是都是规定的值的正方形
    # 如果没有定义,则使用默认的,判断imgaesz的值判断是否为长和宽相同,用于保证至少是和正方形
    print_args(FILE.stem, opt)
    # 输出所有参数
    # 打印出,处理好的参数信息并返回
    # opt变量用于暂时存储这些参数信息-并返回
    return opt


def main(opt):
    # 检查环境/打印参数,主要是requrement.txt的包是否安装,用彩色显示设置的参数
    check_requirements(exclude=('tensorboard', 'thop'))  # 用于检测  requiremants.txt  内的依赖包是否完成了安装
    run(**vars(opt))  # 执行run函数并把值传入,图片加载,图片保存,以及图片识别都在run函数内去执行


# 命令使用
# python detect.py --weights runs/train/exp_yolov5s/weights/best.pt --source  data/images/fishman.jpg # webcam
# 完成导包步奏之后接下来
# 就会执行__name__的内的2个方法
if __name__ == "__main__":
    opt = parse_opt()
    # 负责解析命令行传来的参数 python detect.py --weights runs/train/exp_yolov5s/weights/best.pt --source  data/images/fishman.jpg
    main(opt)
    # 传值给main函数   执行定义号的main函数

免费评分

参与人数 7吾爱币 +13 热心值 +6 收起 理由
xiaolinnnn + 1 + 1 谢谢@Thanks!
luohaofan + 1 + 1 我很赞同!
AwChuKin + 1 + 1 我很赞同!
angrebobo + 1 大佬牛逼
从白嫖到不嫖 + 1 + 1 我喜欢这种一看就懂的
minblack3 + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

minblack3 发表于 2022-7-17 20:22
好详细,太厉害了!!
weimeng555 发表于 2022-7-31 05:23
Onesade 发表于 2022-8-20 01:28
动物园园长 发表于 2022-11-13 14:21
感谢大佬
dwshi666 发表于 2022-11-21 12:30
👍👍👍👍👍
linxi321 发表于 2023-3-31 21:35
大佬好强
Do_zh 发表于 2023-4-10 14:21
这注释写的无敌。
williamvan 发表于 2023-7-24 10:57
很详细呀,论坛里大佬真是厉害。
DiGua3 发表于 2023-8-4 17:38
给大佬敬茶!!牛皮哦
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 17:16

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表