深度学习YOLO抽烟行为检测 - python opencv 计算机竞赛

文章目录

  • 1 前言
  • 1 课题背景
  • 2 实现效果
  • 3 Yolov5算法
    • 3.1 简介
    • 3.2 相关技术
  • 4 数据集处理及实验
  • 5 部分核心代码
  • 6 最后

1 前言

🔥 优质竞赛项目系列,今天要分享的是

🚩 基于深度学习YOLO抽烟行为检测

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🥇学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:4分

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

1 课题背景

公共场合抽烟的危害很大,国家也相应地出台了在公共场合禁烟的政策。以前实行相关的政策都是靠工作人员巡逻发现并出言禁止,这样做效率很低下。计算机视觉领域发展迅速,而抽烟检测也属于一种计算机视觉目标检测的行为,可以采用目标检测的方法来实现。目前,目标检测在很多领域都取得显著成就,但是在抽烟检测领域方面进行研究却几乎没有。该研究可以有效节省成本,对公共场合禁烟政策的实行有很大的推动作用。

2 实现效果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

左图为原图,右图为推理后的图片,以图片方式展示,视频流和实时流也能达到这个效果,由于视频转GIF大小原因,这里暂不演示。

3 Yolov5算法

3.1 简介

YOLO系列是基于深度学习的回归方法。该系列陆续诞生出YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5。YOLOv5算法,它是一种单阶段目标检测的算法,该算法可以根据落地要求灵活地通过chaneel和layer的控制因子来配置和调节模型,所以在比赛和落地中应用比较多。同时它有YOLOv5x、YOLOv5l、YOLOv5m、YOLOv5s四种模型。
具有以下优点:

  • 在pytorch环境下编写;
  • 可以很容易编译成ON⁃NX和Core ML;
  • 运行速度很快,每秒可以达到140FPS的速度;
  • 模型精度高;
  • 集成了YOLOv3和YOLOv4的部分优秀特性,进行了推陈出新的改进。

3.2 相关技术

Mosaic数据增强

Mosaic数据增强技术采用了四张图片的随机缩放、随机剪裁、随机排布的方式对数据进行拼接,相比CutMix数据增强多用了两张图片。在目标识别过程中,要识别的目标有大目标、中等目标、小目标,并且三种目标的占比例不均衡,其中,小目标的数量是最多的,但是出现的频率很低,这种情况就会导致在bp时对小目标的优化不足,模型正确识别小目标的难度比识别中、大目标的难度要大很多,于是对于小目标来说很容易出现误检和漏检的情况。Mosaic数据增强技术做出改进后,上述的问题得到有效的解决。
该技术的优点是:

  • 丰富了数据集,采用“三个随机”的方式对数据进行拼接丰富了检测的数据集,尤其是随机缩放增加了很多小目标,克服了小目标的不足,让网络的鲁棒性得到提高;
  • 减少GPU的使用,在Mosaic增强训练时,四张图片拼接在一起,GPU可以直接计算四张图片的数据,让Mini-batch的大小减少了很多,这使得一个GPU就可以达到比较可观的效果。
    在这里插入图片描述

自适应anchor
自适应anchor是check_anchors函数通过遗传算法与Kmeans迭代算出的最大可能召回率的anchor组合。在网络模型的训练过程中,网络在初始化的锚框的基础上输出预测框,然后与真实框groundtruth进行对比,计算两个框之间的差值,再根据差值进行反向更新,迭代网络参数,最后求出最佳的锚框值。自适应的anchor能够更好地配合网络训练,提高模型的精度,减少对anchor的设计难度,具有很好的实用性。

自适应图片缩放
为了提高模型的推理速度,YOLOv5提出自适应图片缩放,根据长宽比对图像进行缩放,并添加最少的黑边,减少计算量。该方法是用缩放后的长边减去短边再对32进行取余运算,求出padding。在训练时并没有采用缩减黑边的方法,该方法只是在测试模型推理的时候才使用,这样提高了目标检测的准确率和速度。

Focus结构
该结构采用切片操作,将特征切片成四份,每一份将当成下采样的特征,然后在channel维度进行concat。例如:原始608 608
3的数据图片,经过切片操作先变成304 304 12的特征图,再经过一次32个卷积核的卷积操作,变成304 304 32的特征图。
在这里插入图片描述
在这里插入图片描述
CSP结构
YOLOv5中的CSP[5]结构应用于两处,一处是CSP1_X结构应用于Backbone的主干网络中,另一处的CSP2_X结构应用于Neck中,用于加强网络的特征融合的能力。CSPNet主要从网络结构设计的角度解决推理中从计算量很大的问题。该结构的优点有:1)增强CNN的学习能力,使得模型在轻量化的同时保持较高的准确性;2)减低计算的瓶颈问题;3)减低内存的分险。

PFN+PAN结构
这个结构是FPN和PAN的联合。FPN是自顶向下的,将高层的特征信息通过上采样的方式进行传递融合,得到进行预测的特征图,而PAN正好与FPN的方向是相反的方向,它是自底向上地采取特征信息。两个结构各自从不同的主干层对不同的检测层进行参数聚合。两个结构的强强联合让得到的特征图的特征更加明显和清楚。

Bounding box的损失函数
Bounding
box损失函数[6]增加了相交尺度的衡量方式,有效缓解了当两个框不相交和两个框大小完全相同的两种特殊情况。因为当预测框和目标框不相交时,IOU=0,无法反应两个框距离的远近的时候,此时的损失函数不可导;两个框大小完全相同,两个IOU也相同,IOU_LOSS无法区分以上两种特殊情况。

nms非极大值抑制
在目标检测过程的后续处理中,对于大量的目标框的筛选问题,通常会进行nms操作,以此来达到一个不错的效果。YO⁃LOv5算法同样采用了加权的nms操作。

4 数据集处理及实验

数据集准备

由于目前针对吸烟图片并没有现成的数据集,我们使用Python爬虫利用关键字在互联网上获得的图片数据,编写程序爬了1w张,筛选下来有近1000张可用,以及其他途径获取到的,暂时可用数据集有5k张,

深度学习图像标注软件众多,按照不同分类标准有多中类型,本文使用LabelImg单机标注软件进行标注。LabelImg是基于角点的标注方式产生边界框,对图片进行标注得到xml格式的标注文件,由于边界框对检测精度的影响较大因此采用手动标注,并没有使用自动标注软件。

考虑到有的朋友时间不足,博主提供了标注好的数据集和训练好的模型,需要请联系。

数据标注简介

通过pip指令即可安装

pip install labelimg

在命令行中输入labelimg即可打开

在这里插入图片描述

5 部分核心代码



    # data/smoke.yaml


    # COCO 2017 dataset http://cocodataset.org
    # Download command: bash yolov5/data/get_coco2017.sh
    # Train command: python train.py --data ./data/coco.yaml
    # Dataset should be placed next to yolov5 folder:
    #   /parent_folder
    #     /coco
    #     /yolov5


    # train and val datasets (image directory or *.txt file with image paths)
    train: data\train.txt  # 上面我们生成的train,根据自己的路径进行更改
    val: data\test.txt  # 上面我们生成的test
    #test: ../coco/test-dev2017.txt  # 20k images for submission to https://competitions.codalab.org/competitions/20794
    
    # number of classes
    nc: 1   #训练的类别
    
    # class names
    names: ['smoke']
    
    # Print classes
    # with open('data/coco.yaml') as f:
    #   d = yaml.load(f, Loader=yaml.FullLoader)  # dict
    #   for i, x in enumerate(d['names']):
    #     print(i, x)


    # model/yolov5s.yaml

    # parameters
    nc: 1  # number of classes
    depth_multiple: 0.33  # model depth multiple
    width_multiple: 0.50  # layer channel multiple
    
    # anchors
    anchors:
      - [116,90, 156,198, 373,326]  # P5/32
      - [30,61, 62,45, 59,119]  # P4/16
      - [10,13, 16,30, 33,23]  # P3/8
    
    # YOLOv5 backbone
    backbone:
      # [from, number, module, args]
      [[-1, 1, Focus, [64, 3]],  # 0-P1/2
       [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
       [-1, 3, BottleneckCSP, [128]],
       [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
       [-1, 9, BottleneckCSP, [256]],
       [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
       [-1, 9, BottleneckCSP, [512]],
       [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32
       [-1, 1, SPP, [1024, [5, 9, 13]]],
      ]
    
    # YOLOv5 head
    head:
      [[-1, 3, BottleneckCSP, [1024, False]],  # 9
    
       [-1, 1, Conv, [512, 1, 1]],
       [-1, 1, nn.Upsample, [None, 2, 'nearest']],
       [[-1, 6], 1, Concat, [1]],  # cat backbone P4
       [-1, 3, BottleneckCSP, [512, False]],  # 13
    
       [-1, 1, Conv, [256, 1, 1]],
       [-1, 1, nn.Upsample, [None, 2, 'nearest']],
       [[-1, 4], 1, Concat, [1]],  # cat backbone P3
       [-1, 3, BottleneckCSP, [256, False]],
       [-1, 1, nn.Conv2d, [na * (nc + 5), 1, 1]],  # 18 (P3/8-small)
    
       [-2, 1, Conv, [256, 3, 2]],
       [[-1, 14], 1, Concat, [1]],  # cat head P4
       [-1, 3, BottleneckCSP, [512, False]],
       [-1, 1, nn.Conv2d, [na * (nc + 5), 1, 1]],  # 22 (P4/16-medium)
    
       [-2, 1, Conv, [512, 3, 2]],
       [[-1, 10], 1, Concat, [1]],  # cat head P5
       [-1, 3, BottleneckCSP, [1024, False]],
       [-1, 1, nn.Conv2d, [na * (nc + 5), 1, 1]],  # 26 (P5/32-large)
    
       [[], 1, Detect, [nc, anchors]],  # Detect(P5, P4, P3)
      ]


    # 训练部分主函数


    if __name__ == '__main__':
        check_git_status()
        parser = argparse.ArgumentParser()
        parser.add_argument('--epochs', type=int, default=300)
        parser.add_argument('--batch-size', type=int, default=16)
        parser.add_argument('--cfg', type=str, default='models/yolov5s.yaml', help='*.cfg path')
        parser.add_argument('--data', type=str, default='data/smoke.yaml', help='*.data path')
        parser.add_argument('--img-size', nargs='+', type=int, default=[640, 640], help='train,test sizes')
        parser.add_argument('--rect', action='store_true', help='rectangular training')
        parser.add_argument('--resume', action='store_true', help='resume training from last.pt')
        parser.add_argument('--nosave', action='store_true', help='only save final checkpoint')
        parser.add_argument('--notest', action='store_true', help='only test final epoch')
        parser.add_argument('--noautoanchor', action='store_true', help='disable autoanchor check')
        parser.add_argument('--evolve', action='store_true', help='evolve hyperparameters')
        parser.add_argument('--bucket', type=str, default='', help='gsutil bucket')
        parser.add_argument('--cache-images', action='store_true', help='cache images for faster training')
        parser.add_argument('--weights', type=str, default='', help='initial weights path')
        parser.add_argument('--name', default='', help='renames results.txt to results_name.txt if supplied')
        parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
        parser.add_argument('--adam', action='store_true', help='use adam optimizer')
        parser.add_argument('--multi-scale', action='store_true', help='vary img-size +/- 50%')
        parser.add_argument('--single-cls', action='store_true', help='train as single-class dataset')
        opt = parser.parse_args()
        opt.weights = last if opt.resume else opt.weights
        opt.cfg = check_file(opt.cfg)  # check file
        opt.data = check_file(opt.data)  # check file
        print(opt)
        opt.img_size.extend([opt.img_size[-1]] * (2 - len(opt.img_size)))  # extend to 2 sizes (train, test)
        device = torch_utils.select_device(opt.device, apex=mixed_precision, batch_size=opt.batch_size)
        if device.type == 'cpu':
            mixed_precision = False
    
        # Train
        if not opt.evolve:
            tb_writer = SummaryWriter(comment=opt.name)
            print('Start Tensorboard with "tensorboard --logdir=runs", view at http://localhost:6006/')
            train(hyp)
    
        # Evolve hyperparameters (optional)
        else:
            tb_writer = None
            opt.notest, opt.nosave = True, True  # only test/save final epoch
            if opt.bucket:
                os.system('gsutil cp gs://%s/evolve.txt .' % opt.bucket)  # download evolve.txt if exists
    
            for _ in range(10):  # generations to evolve
                if os.path.exists('evolve.txt'):  # if evolve.txt exists: select best hyps and mutate
                    # Select parent(s)
                    parent = 'single'  # parent selection method: 'single' or 'weighted'
                    x = np.loadtxt('evolve.txt', ndmin=2)
                    n = min(5, len(x))  # number of previous results to consider
                    x = x[np.argsort(-fitness(x))][:n]  # top n mutations
                    w = fitness(x) - fitness(x).min()  # weights
                    if parent == 'single' or len(x) == 1:
                        # x = x[random.randint(0, n - 1)]  # random selection
                        x = x[random.choices(range(n), weights=w)[0]]  # weighted selection
                    elif parent == 'weighted':
                        x = (x * w.reshape(n, 1)).sum(0) / w.sum()  # weighted combination
    
                    # Mutate
                    mp, s = 0.9, 0.2  # mutation probability, sigma
                    npr = np.random
                    npr.seed(int(time.time()))
                    g = np.array([1, 1, 1, 1, 1, 1, 1, 0, .1, 1, 0, 1, 1, 1, 1, 1, 1, 1])  # gains
                    ng = len(g)
                    v = np.ones(ng)
                    while all(v == 1):  # mutate until a change occurs (prevent duplicates)
                        v = (g * (npr.random(ng) < mp) * npr.randn(ng) * npr.random() * s + 1).clip(0.3, 3.0)
                    for i, k in enumerate(hyp.keys()):  # plt.hist(v.ravel(), 300)
                        hyp[k] = x[i + 7] * v[i]  # mutate
    
                # Clip to limits
                keys = ['lr0', 'iou_t', 'momentum', 'weight_decay', 'hsv_s', 'hsv_v', 'translate', 'scale', 'fl_gamma']
                limits = [(1e-5, 1e-2), (0.00, 0.70), (0.60, 0.98), (0, 0.001), (0, .9), (0, .9), (0, .9), (0, .9), (0, 3)]
                for k, v in zip(keys, limits):
                    hyp[k] = np.clip(hyp[k], v[0], v[1])
    
                # Train mutation
                results = train(hyp.copy())
    
                # Write mutation results
                print_mutation(hyp, results, opt.bucket)
    
                # Plot results
                # plot_evolution_results(hyp)



6 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/165975.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Parity Game——种类并查集、权值并查集、离散化

题目描述 思路 怎么得到这个序列中每一段的关系&#xff1f; 我们可以把这个只包含0和1的序列看作一个数组&#xff0c;0表示当前位置为0&#xff0c;1表示当前位置为1&#xff0c;利用前缀和的性质可以知道某一段中所包含的1的数量sum1 a[r] - a[l-1] 如果sum1为偶数&…

Rust开发——切片(slice)类型

1、什么是切片 在 Rust 中&#xff0c;切片&#xff08;slice&#xff09;是一种基本类型和序列类型。在 Rust 官方文档中&#xff0c;切片被定义为“对连续序列的动态大小视图”。 但在rust的Github 源码中切片被定义如下&#xff1a; 切片是对一块内存的视图&#xff0c;表…

如何隐藏Selenium特征实现自动化网页采集

Selenium是一个流行的自动化网页测试工具&#xff0c;可以通过模拟用户在Chrome浏览器中的操作来完成网站的测试。然而&#xff0c;有些网站会检测浏览器是否由Selenium驱动&#xff0c;如果是&#xff0c;就会返回错误的结果或拒绝访问。为了避免这种情况&#xff0c;我们需要…

多线程编程

1 线程的使用 1.1 为什么要使用多线程 在编写代码时&#xff0c;是否会遇到以下的场景会感觉到难以下手&#xff1f; 要做 2 件事&#xff0c;一件需要阻塞等待&#xff0c;另一件需要实时进行。例如播放器&#xff1a;一边在屏幕上播放视频&#xff0c;一边在等待用户的按…

中间件安全:Apache 目录穿透.(CVE-2021-41773)

中间件安全&#xff1a;Apache 目录穿透.&#xff08;CVE-2021-41773&#xff09; Apache 的 2.4.49、2.4.50 版本 对路径规范化所做的更改中存在一个路径穿越漏洞&#xff0c;攻击者可利用该漏洞读取到Web目录外的其他文件&#xff0c;如系统配置文件、网站源码等&#xff0c…

Polygon zkEVM协议治理、升级及其流程

1. 引言 随着Polygon社区开发者和内部团队的测试深入&#xff0c;当前版本的Polygon zkEVM不可避免地需更新和某些升级。 为激励开发者对Polygon zkEVM做battle-test&#xff0c;已启动了bug-bounty&#xff1a; Rewards by Threat Level 由于zk-Rollup生态系统还处于萌芽阶…

算法设计与分析复习--贪心(二)

文章目录 上一篇哈夫曼编码单源最短路最小生成树Kruskal算法Prim算法 多机调度问题下一篇 上一篇 算法设计与分析复习–贪心&#xff08;一&#xff09; 哈夫曼编码 产生这种前缀码的方式称为哈夫曼树 哈夫曼树相关习题AcWing 148. 合并果子 #include <iostream> #inc…

LDO线性稳压器要不要并联二极管?

昨天介绍过了LDO是什么东西&#xff0c;那么对于它的应用场景是怎么的呢&#xff1f;LDO要不要并联二极管呢&#xff1f; 一般来说&#xff0c;LDO是不需要并联二极管的。 看下图第一个是典型电路&#xff0c;第二个是带可调节电压功能的LDO典型电路&#xff0c;从图里就可以…

设计模式-组合模式-笔记

“数据结构”模式 常常有一些组件在内部具有特定的数据结构&#xff0c;如果让客户程序依赖这些特定数据结构&#xff0c;将极大地破坏组件的复用。这时候&#xff0c;将这些特定数据结构封装在内部&#xff0c;在外部提供统一的接口&#xff0c;来实现与特定数据结构无关的访…

一起Talk Android吧(第五百五十四回:分享一个Retorfit使用错误的案例)

文章目录 1. 案例场景2. 案例现象3. 原因分析和解决方案3.1 原因分析3.2 解决方案4. 经验总结各位看官们大家好,上一回中咱们说的例子是"解析Retrofit返回的数据",本章回中将分享一个 Retrofit使用错误的案例。闲话休提,言归正转,让我们一起Talk Android吧! 1. …

三层交换机实现不同VLAN间通讯

默认时&#xff0c;同一个VLAN中的主机才能彼此通信&#xff0c;那么交换机上的VLAN用户之间如何通信&#xff1f; 要实现VLAN之间用户的通信&#xff0c;就必须借助路由器或三层交换机来完成。 下面以三层交换机为例子说明&#xff1a; 注意&#xff1a; 1.交换机与三层交换…

HWS-CTF-第七期山大站-inverse

文章目录 inversemainworkread_intread_n 思路onegadget exp 第一次真正意义上独立在比赛中做出题目来了&#xff0c;距离真正意义接触CTF-PWN差不多正好两个月。但由于不知道靶场要自己开而且端口每次自己打开会改&#xff0c;交flag稍微晚了些&#xff08;我太菜了&#xff0…

Java中锁的深入理解

目录 对象头的理解 Monitor&#xff08;锁&#xff09; 锁类型 偏向锁 偏向锁的优化机制 轻量级锁 重量级锁 对象头的理解 在32位Java虚拟机中普通对象的对象头是占用8个字节&#xff0c;其中4个字节为Mark Word。用来存储对象的哈希值&#xff0c;对象创建后在JVM中的…

【顺序表的实现】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 1. 数据结构相关概念 1、什么是数据结构 2、为什么需要数据结构&#xff1f; 2、顺序表 1、顺序表的概念及结构 1.1 线性表 2、顺序表分类 3、动态顺序表的实现 总…

ssm+vue的高校疫情防控管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的高校疫情防控管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结…

【C++入门】拷贝构造运算符重载

目录 1. 拷贝构造函数 1.1 概念 1.2 特征 1.3 常用场景 2. 赋值运算符重载 2.1 运算符重载 2.2 特征 2.3 赋值运算符 前言 拷贝构造和运算符重载是面向对象编程中至关重要的部分&#xff0c;它们C编程中的一个核心领域&#xff0c;本期我详细的介绍拷贝构造和运算符重载。 1. …

面向对象与面向过程的区别

面向对象 以对象为中心&#xff0c;把数据封装成为一个整体&#xff0c;其他数据无法直接修改它的数据&#xff0c;将问题分解成不同对象&#xff0c;然后给予对象相应的属性和行为。 面向过程 关注代码过程&#xff0c;直接一程序来处理数据&#xff0c;各模块之间有调用与…

OSI参考模型

目录 一. OSI参考模型的各层功能二. 网络排错三. 网络安全四. 实体、协议、服务和服务访问点SAP五. TCP IP体系结构 一. OSI参考模型的各层功能 \quad \quad \quad \quad 我们首先来看应用层实现的功能 每个字段的各种取值所代表的意思 \quad \quad 比如要保存的文件内容是ab…

OpenAI 董事会与 Sam Altman 讨论重返 CEO 岗位事宜

The Verge 援引多位知情人士消息称&#xff0c;OpenAI 董事会正在与 Sam Altman 讨论他重新担任首席执行官的可能性。 有一位知情人士表示&#xff0c;Altman 对于回归公司一事的态度暧昧&#xff0c;尤其是在他没有任何提前通知的情况下被解雇后。他希望对公司的治理模式进行重…

【开源】基于Vue.js的高校实验室管理系统的设计和实现

项目编号&#xff1a; S 015 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S015&#xff0c;文末获取源码。} 项目编号&#xff1a;S015&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…