Datawhale AI 夏令营 CV方向 Task03

上篇笔记(Datawhale AI 夏令营 CV方向 Task02-CSDN博客)从增加训练集、增大模型参数量、修改数据增强参数等方向进行提分,本篇笔记继续探究提分思路。但由于本人水平有限(QAQ代码能力差是硬伤),很多想法都没有具体实现。

数据集查看

上篇笔记中调整了yolov8n的数据增强参数,于是想试试增大参数量有没有明显提升(放缩定律),这里使用yolov8m按相同的参数进行训练,结果仅提升0.02个点,效果并不明显。说明提升瓶颈并不在参数量,还有其他因素限制了模型的能力。

首先从数据集上找原因,采用以下代码查看数据集和标注(需要在windows本地运行,服务器没有图形化显示界面):

import cv2
import os
import json
import numpy as np

vpath = './video'
lpath = './label'
spath = './show'

for vid in os.listdir(vpath):
    # print(vid)
    if vid.endswith('.mp4'):
        lab = vid.split('.mp4')[0]+'.json'
        vid_path = os.path.join(vpath, vid)
        lab_path = os.path.join(lpath, lab)
        with open(lab_path, 'r', encoding='utf-8') as f:
            content = f.read()
            frame_list = json.loads(content)
            # print(frame_list)
            # assert False
        cnt = 0
        cap = cv2.VideoCapture(vid_path)
        while cap.isOpened():
            #video.read() : 一次读取视频中的每一帧,会返回两个值;
            #res : 为bool类型表示这一帧是否真确读取,正确读取为True,如果文件读取到结尾,它的返回值就为False;
            #frame : 表示这一帧的像素点数组
            ret, frame = cap.read()
            if frame is None: 
                break
            
            for i in range(cnt, len(frame_list)):
                if frame_list[i]['frame_id'] > cnt:
                    break
                elif frame_list[i]['frame_id'] < cnt:
                    continue
                else:
                    bbox = frame_list[i]['bbox']
                    cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color=(0, 0, 255))
            cnt += 1

            #frame[fgmask>0] = 0

            if ret == True:
                cv2.imshow(vid, frame)
                
            #10 : 表示一帧等待10毫秒在进入下一帧, 0xFF : 表示键入键 27 = esc
            if cv2.waitKey(10) & 0xFF == 27 :
                break 
            #video.release()释放视频
        cap.release()
        cv2.destroyAllWindows()

发现很多数据集的场景相似度都非常高:

如图所示:14~33在同一场景进行录制,34~52在同一场景录制。按照之前的数据集划分方法(将前40个视频分为训练集、其余分为验证集),将导致三点缺陷:

1. 14~33的图片经过过多训练,不利于样本平衡

2. 验证集只包含40~52,验证场景单一

3. 34~52视频高度相似,却分别被划分进训练集和验证集,导致模型在验证集上训练

在过滤掉一些重复视频重新划分完数据集后,使用yolov8m训练,结果不升反降,这促使我进一步对数据集探索。

经过细致的观察,我发现34~52场景中有很多路过的电动车,违停的白色面包车也启动离开,清洁工的保洁三轮车也时不时会移动换位置,当它们运动的时候是不会出现标注的:(图中红框的目标在视频中是运动的,标注文件中没有对它们进行标注)

这启发我做进一步思考:

YOLO目标检测的输入是静态图片(即便推理时可以输入视频,但它也是一张一张进行推理预测),这使它无法判断物体的运动情况。对于上图的场景,YOLO完全可以认为电动车和面包车属于违停,因为它们出现在了违停的“位置”。

对于此种情况,我想出以下几种思路:

1. 改用视频目标检测模型,使得模型可以分析帧和帧之间的关联,有助于模型理解物体的运动

2. 采用YOLO+多目标跟踪模型,当检测框出现移动时,便可以进行排除

3. 对输入图像进行处理,用掩膜将运动的物体盖住

视频目标检测模型

关于视频目标检测模型,我找到了MMTracking工具箱。

MMTracking 是 OpenMMLab 的一体化视频目标感知平台,同时支持了视频目标检测、单目标跟踪、多目标跟踪等多种任务和算法,填补了这些领域内基准开源平台的空白。

在 MMTracking 中,作者复现集成了各个领域的主流算法,包括

  • 视频目标检测:DFF, FGFA, SELSA

  • 多目标跟踪:SORT, DeepSORT, Tracktor

  • 单目标跟踪: SiameseRPN++

这些方法在保证了高效的训练、推理的基础上,有些模型甚至超出官方实现。

以下是MMTracking的官方文档,由于代码水平和时间精力实在有限,没有去尝试,想进一步提分的同学可以试试。

欢迎来到 MMTracking 的中文文档! — MMTracking 0.14.0 文档

YOLO+多目标跟踪模型

看似是一个合理的思路,但是还存在一些问题。采用这种方案必须标注视频中出现的所有机动车和非机动车(垃圾桶满溢、违法经营和运动无关),无论它们是否违规。而且对于移动的物体,它们每帧之间的位置都会变化,想要全部标完是个极大的工作量。

因此该方案似乎不可行,除非能找到训练好的机动车、非机动车检测模型或相关数据集。

掩膜将运动的物体盖住

使用opencv提供的背景差分函数createBackgroundSubtractorMOG2来实现此功能。

该方法可以用来做运动检测,用法:

 mask = cv2.createBackgroundSubtractorMOG2( history=100,
                                            varThreshold=25,
                                            detectShadows=false
                                            )
  • history:用于训练背景的帧数,默认帧数为500帧,如果不动手设置learingRate,history就被用于计算当前的learningRate, 此时history越大,learningRate越小,背景更新越慢;
  • varThreshold:方差阈值,用于判断当前像素是前景还是背景。一般默认为16,如果光照变化明显,如阳光下的水面,建议设为25,值越大灵敏度越低。
  • detectShadows:是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,一般设置为false;

完整代码:

import cv2
import os
import json
import numpy as np

vpath = './video'
lpath = './label'
spath = './show'

fgbg = cv2.createBackgroundSubtractorMOG2(history=100)

for vid in os.listdir(vpath):
    # print(vid)
    if vid.endswith('.mp4'):
        lab = vid.split('.mp4')[0]+'.json'
        vid_path = os.path.join(vpath, vid)
        lab_path = os.path.join(lpath, lab)
        with open(lab_path, 'r', encoding='utf-8') as f:
            content = f.read()
            frame_list = json.loads(content)
            # print(frame_list)
            # assert False
        cnt = 0
        cap = cv2.VideoCapture(vid_path)
        while cap.isOpened():
            #video.read() : 一次读取视频中的每一帧,会返回两个值;
            #res : 为bool类型表示这一帧是否真确读取,正确读取为True,如果文件读取到结尾,它的返回值就为False;
            #frame : 表示这一帧的像素点数组
            ret, frame = cap.read()
            if frame is None: 
                break
            
            fgmask = fgbg.apply(frame)
            
            kernel = np.ones((5, 5), np.uint8)
            # fgmask = cv2.erode(fgmask, kernel, iterations=1)

            for i in range(cnt, len(frame_list)):
                if frame_list[i]['frame_id'] > cnt:
                    break
                elif frame_list[i]['frame_id'] < cnt:
                    continue
                else:
                    bbox = frame_list[i]['bbox']
                    cv2.rectangle(frame, (bbox[0], bbox[1]), (bbox[2], bbox[3]), color=(0, 0, 255))
            cnt += 1

            frame[fgmask>0] = 0

            if ret == True:
                cv2.imshow(vid, frame)
                # print(frame.shape)
                cv2.imshow('mask', fgmask)
            #10 : 表示一帧等待10毫秒在进入下一帧, 0xFF : 表示键入键 27 = esc
            if cv2.waitKey(10) & 0xFF == 27 :
                break 
            #video.release()释放视频
        cap.release()
        cv2.destroyAllWindows()

效果如下:黑色部分是遮住运动物体的掩膜。

效果并不理想,因行人运动的原因,有些掩膜还会遮住待检测的目标。

有点黔驴技穷了(QAQ)

总结

第一次参加Datawhale的夏令营活动,第一次参加CV竞赛,希望以后能有更多相关活动,丰富部署模型用于实际场景的经历。

  • 18
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值