草庐IT

视频异常检测数据集 (ShanghaiTech) 及其I3D特征转换

因吉 2023-08-23 原文

文章目录

1 概述

ShanghaiTech是一个中型数据集,基本信息如下:

  1. 训练集:330个正常视频;
  2. 测试集:107个异常视频,已被划分为多个帧,包含13个异常事件,且带有。
    该数据集的一个示意如下图:

为了使得数据集适应MIL的场景,Zhong等人依据类别平衡的准则将整个数据集重新划分。划分的索引如下:
https://github.com/jx-zhong-for-academic-purpose/GCN-Anomaly-Detection

2 视频数据转换为I3D包

这里使用的预训练模型作为特征提取器,其中Mixed_5c层作为返回特征。

2.1 下载Torch-I3D模型:

地址如下:
https://github.com/piergiaj/pytorch-i3d
下载之后打开models:

这里注意flow和rgb的区别:

  1. rgb:原始视频作为输入,通道为3;
  2. flow:视频的光流作为输入,通道为2;

关于光流的使用,可以参照我的博客:
https://inkiyinji.blog.csdn.net/article/details/127622063
这里使用的flownet而非flownet2,因为我的电脑没有GPU。。。

2.2 将视频转换为包

这里以单个视频为示意。设置划分后的最大视频片段数为32,每个片段的帧数固定为16:

  • 对于视频总帧数低于或者等于512帧的视频,从第1帧开始以每16帧为单位划分,最后一帧如果不足16帧,则替换为视频的后16帧;
  • 对于其它情况,将视频平分为32份,其中每一个片段在帧数维resize为16。

具体代码如下:

import decord
import os
import numpy as np
import torch
from imageio.v2 import imread
from gluoncv.torch.data.transforms.videotransforms import video_transforms, volume_transforms
from pytorch_i3d import InceptionI3d


class Video2I3D:

    def __init__(self, path, num_snippet=32, snippet_size=16, input_type="video", transformer=None):
        """
        Args:
            path: 视频存储路径
            num_snippet: 视频划分后的最大片段数
            snippet_size: 每个片段的数量,不得超过16,否则无法得到单向量;不得小于9,否则无法完成卷积
            input_type: 输入的数据类型:原始视频 (video) 或者视频帧 (frame)
            transformer: 视频转换器
        """
        self.path = path
        self.num_snippet = num_snippet
        self.snippet_size = snippet_size
        assert 9 <= self.snippet_size <= 16

        if input_type == "video":
            self.video = self.__load_video__()
        else:
            self.video = self.__load__frame()
        # self.video = np.transpose(self.video, [0, 3, 1, 2])

        self.transformer = self.__get_transformer__() if transformer is None else transformer
        self.i3d_net = self.__get_i3d_extractor()

    def fit(self):
        self.video = self.transformer(self.video)

        """Split each video"""
        # The frame number less than the split requirement
        if self.num_frame <= self.num_snippet * self.snippet_size:
            start_idx = np.arange(0, self.num_frame, self.snippet_size).tolist()
            end_idx = start_idx[1:] + [self.num_frame]
            if end_idx[-1] - start_idx[-1] < self.snippet_size:
                start_idx[-1] = end_idx[-1] - self.snippet_size
        else:
            start_idx = np.arange(0, self.num_frame, int(np.ceil(self.num_frame / self.num_snippet))).tolist()
            end_idx = start_idx[1:] + [self.num_frame]
            new_video = []
            for i, j in zip(start_idx, end_idx):
                video = self.video[:, i: j]
                video = video.resize_([3, self.snippet_size, video.shape[2], video.shape[3]])
                new_video.append(video)
            self.video = torch.hstack(new_video)
            start_idx = np.arange(0, self.num_snippet * self.snippet_size, self.snippet_size).tolist()
            end_idx = start_idx[1:] + [self.num_snippet * self.snippet_size]

        self.video = self.video.unsqueeze(0)
        bag = []
        for i, j in zip(start_idx, end_idx):
            video = self.video[:, :, i: j]
            if video.shape[2] == self.snippet_size:
                ins = self.i3d_net.extract_features(video).reshape(1, 1024)
                bag.append(ins)

        return torch.vstack(bag)

    def __load_video__(self):
        vr = decord.VideoReader(self.path)
        self.num_frame = vr.num_frame
        frame_id_list = np.arange(0, vr.num_frame).tolist()
        video = vr.get_batch(frame_id_list).asnumpy()
        # video_data = np.transpose(video_data, [0, 3, 1, 2])
        return video

    def __load__frame(self):
        frame_list = os.listdir(self.path)
        self.num_frame = len(frame_list)
        video = []
        for frame_name in frame_list:
            frame_path = os.path.join(self.path, frame_name)
            frame = imread(frame_path)
            frame = frame.reshape([1, frame.shape[0], frame.shape[1], frame.shape[2]])
            video.append(frame)

        video = np.vstack(video)

        return video

    @staticmethod
    def __get_transformer__():
        transform_fn = video_transforms.Compose([video_transforms.Resize(256, interpolation='bilinear'),
                                                 video_transforms.CenterCrop(size=(224, 224)),
                                                 volume_transforms.ClipToTensor(),
                                                 video_transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                                                            std=[0.229, 0.224, 0.225])])
        return transform_fn

    @staticmethod
    def __get_i3d_extractor():
        net = InceptionI3d(name="Mixed_5c")
        net.load_state_dict(torch.load("models/rgb_imagenet.pt"))
        return net

2.3 代码测试

以视频作为输入的代码:

if __name__ == '__main__':
    vi = Video2I3D(path="D:/Data/VAD/ShanghaiTech/training/videos/01_001.avi")
    print(vi.fit().shape)

以视频帧作为输入的代码:

if __name__ == '__main__':
    vi = Video2I3D(path="D:/Data/VAD/ShanghaiTech/testing/frames/01_0014/", input_type="frame")
    print(vi.fit().shape)

输出如下:

torch.Size([17, 1024])

有关视频异常检测数据集 (ShanghaiTech) 及其I3D特征转换的更多相关文章

  1. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  2. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  3. ruby-on-rails - Rails - 乐观锁定总是触发 StaleObjectError 异常 - 2

    我正在学习Rails,并阅读了关于乐观锁的内容。我已将类型为integer的lock_version列添加到我的articles表中。但现在每当我第一次尝试更新记录时,我都会收到StaleObjectError异常。这是我的迁移:classAddLockVersionToArticle当我尝试通过Rails控制台更新文章时:article=Article.first=>#我这样做:article.title="newtitle"article.save我明白了:(0.3ms)begintransaction(0.3ms)UPDATE"articles"SET"title"='dwdwd

  4. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  5. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  6. ruby - 在 Ruby 中重新分配常量时抛出异常? - 2

    我早就知道Ruby中的“常量”(即大写的变量名)不是真正常量。与其他编程语言一样,对对象的引用是唯一存储在变量/常量中的东西。(侧边栏:Ruby确实具有“卡住”引用对象不被修改的功能,据我所知,许多其他语言都没有提供这种功能。)所以这是我的问题:当您将一个值重新分配给常量时,您会收到如下警告:>>FOO='bar'=>"bar">>FOO='baz'(irb):2:warning:alreadyinitializedconstantFOO=>"baz"有没有办法强制Ruby抛出异常而不是打印警告?很难弄清楚为什么有时会发生重新分配。 最佳答案

  7. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  8. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  9. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  10. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

随机推荐