視頻數(shù)據(jù)集UCF101的處理與加載(用PyTorch實(shí)現(xiàn))

一 寫在前面

未經(jīng)允許,不得轉(zhuǎn)載鸽斟,謝謝~~~

  1. 之前寫了一篇沒(méi)有使用任何深度學(xué)習(xí)框架來(lái)處理視頻數(shù)據(jù)集的文章:視頻數(shù)據(jù)集UCF101的處理與加載(未使用深度學(xué)習(xí)框架)
  2. 上面的處理方法簡(jiǎn)單直接酗捌,但仍有很多可以優(yōu)化的空間呢诬,這兩天又學(xué)習(xí)了一下PyTorch對(duì)于數(shù)據(jù)集加載的支持:PyTorch入門學(xué)習(xí)(七):數(shù)據(jù)加載與處理
  3. 之前說(shuō)過(guò)要用PyTorch的方法重新實(shí)現(xiàn)一遍對(duì)于UCF101的處理,所以在這里做個(gè)記錄胖缤。這篇文章里僅僅記錄具體的實(shí)現(xiàn)方法尚镰,至于為什么這么做還是點(diǎn)這里哦~~

二 具體目標(biāo)

  1. 按照trainlist(testllist)中的列表去確定要用哪些數(shù)據(jù)集。
  2. 對(duì)于每一個(gè)視頻隨機(jī)取連續(xù)的16幀
  3. 每一幀都減去RGB平均值
  4. 對(duì)于每幀先將大小修改到(182,242)
  5. 然后對(duì)修改過(guò)大小的幀隨機(jī)截取(160,160)
  6. 每次返回視頻表示: x[batch_size,16,3,160,160], 標(biāo)簽值: y[batch_size]

三 基本實(shí)現(xiàn)思路

鑒于我們現(xiàn)在要處理的數(shù)據(jù)集既不是PyTorch直接提供的哪廓,又不符合最通用的ImageFolder存儲(chǔ)格式狗唉,我們就一步步地實(shí)現(xiàn)具體的功能。

  • 跟例程中最大的區(qū)別在于我們組要處理的視頻涡真,而不是單張圖像分俯,那么就把這一步工作放到__getitem__里面去完成。
  • 剩下的變換功能放到transform里面去完成哆料。

具體的步驟如下所示:

  1. 首先缸剪,定義數(shù)據(jù)集的類UCF101,這個(gè)類要繼承dataset這個(gè)抽象類东亦,并實(shí)現(xiàn)__init__ , __len__以及__getitem__這幾個(gè)函數(shù)

    • __init__:完成infolist的讀入及處理還有其他的初始化工作杏节。
    • __len__:返回?cái)?shù)據(jù)集大小
    • __getitem__:返回單個(gè)視頻隨機(jī)連續(xù)16幀的讀取和返回
    • 其他函數(shù)用于支持以上的功能。
  2. 然后,實(shí)現(xiàn)用于特定圖像預(yù)處理的功能拢锹,并封裝成類。

    • 減去RGB的平均值
    • 大小調(diào)整成(182,242)
    • 隨機(jī)截取成(160,160)
    • 轉(zhuǎn)換成Tensor
    • 將它們進(jìn)行組合成(transform)
  3. transform作為上面UCF101類的參數(shù)傳入萄喳,并得到實(shí)例化UCF101得到my_UCF101對(duì)象卒稳。

  4. 最后,將my_UCF101作為torch.utils.data.DataLoader類的形參他巨,并根據(jù)需求設(shè)置自己是否需要打亂順序充坑,批大小...

四 完整代碼

原理的部分不懂的話還是建議回去看看這篇哇:PyTorch入門學(xué)習(xí)(七):數(shù)據(jù)加載與處理
這里就不再贅述,直接貼上源代碼了染突。

from __future__ import print_function, division
import os
import torch
import pandas as pd
from skimage import io, transform
import numpy as np
import random
import torch
import matplotlib.pyplot as plt
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils

# Ignore warnings
import warnings
warnings.filterwarnings("ignore")
plt.ion()   # interactive mode



class ClipSubstractMean(object):
  def __init__(self, b=104, g=117, r=123):
    self.means = np.array((r, g, b))

  def __call__(self, sample):
    video_x,video_label=sample['video_x'],sample['video_label']
    new_video_x=video_x - self.means
    return {'video_x': new_video_x, 'video_label': video_label}


class Rescale(object):
    """Rescale the image in a sample to a given size.

    Args:
        output_size (tuple or int): Desired output size. If tuple, output is
            matched to output_size. If int, smaller of image edges is matched
            to output_size keeping aspect ratio the same.
    """

    def __init__(self, output_size=(182,242)):
        assert isinstance(output_size, (int, tuple))
        self.output_size = output_size

    def __call__(self, sample):
        video_x,video_label=sample['video_x'],sample['video_label']
    
        h, w = video_x.shape[1],video_x[2]
        if isinstance(self.output_size, int):
            if h > w:
                new_h, new_w = self.output_size * h / w, self.output_size
            else:
                new_h, new_w = self.output_size, self.output_size * w / h
        else:
            new_h, new_w = self.output_size

        new_h, new_w = int(new_h), int(new_w)
        new_video_x=np.zeros((16,new_h,new_w,3))
        for i in range(16):
            image=video_x[i,:,:,:]
            img = transform.resize(image, (new_h, new_w))
            new_video_x[i,:,:,:]=img

        return {'video_x': new_video_x, 'video_label': video_label}


class RandomCrop(object):
    """Crop randomly the image in a sample.

    Args:
        output_size (tuple or int): Desired output size. If int, square crop
            is made.
    """

    def __init__(self, output_size=(160,160)):
        assert isinstance(output_size, (int, tuple))
        if isinstance(output_size, int):
            self.output_size = (output_size, output_size)
        else:
            assert len(output_size) == 2
            self.output_size = output_size

    def __call__(self, sample):
        video_x, video_label = sample['video_x'], sample['video_label']

        h, w = video_x.shape[1],video_x.shape[2]
        new_h, new_w = self.output_size

        top = np.random.randint(0, h - new_h)
        left = np.random.randint(0, w - new_w)
         
        new_video_x=np.zeros((16,new_h,new_w,3))
        for i in range(16):
            image=video_x[i,:,:,:]
            image = image[top: top + new_h,left: left + new_w]
            new_video_x[i,:,:,:]=image

        return {'video_x': new_video_x, 'video_label': video_label}


class ToTensor(object):
    """Convert ndarrays in sample to Tensors."""

    def __call__(self, sample):
        video_x, video_label = sample['video_x'], sample['video_label']

        # swap color axis because
        # numpy image: batch_size x H x W x C
        # torch image: batch_size x C X H X W
        video_x = video_x.transpose((0, 3, 1, 2))
        video_x=np.array(video_x)
        video_label = [video_label]
        return {'video_x':torch.from_numpy(video_x),'video_label':torch.FloatTensor(video_label)}


class UCF101(Dataset):
    """UCF101 Landmarks dataset."""

    def __init__(self, info_list, root_dir, transform=None):
        """
        Args:
            info_list (string): Path to the info list file with annotations.
            root_dir (string): Directory with all the video frames.
            transform (callable, optional): Optional transform to be applied
                on a sample.
        """
        self.landmarks_frame = pd.read_csv(info_list,delimiter=' ', header=None)
        self.root_dir = root_dir
        self.transform = transform
            
    def __len__(self):
        return len(self.landmarks_frame)

    # get (16,240,320,3)
    def __getitem__(self, idx):
        video_path = os.path.join(self.root_dir,self.landmarks_frame.iloc[idx, 0])
        video_label=self.landmarks_frame.iloc[idx,1]
        video_x=self.get_single_video_x(video_path)
        sample = {'video_x':video_x, 'video_label':video_label}

        if self.transform:
            sample = self.transform(sample)
        return sample


    def get_single_video_x(self,video_path):
        slash_rows=video_path.split('.')
        dir_name=slash_rows[0]
        video_jpgs_path=os.path.join(self.root_dir,dir_name)
        # get the random 16 frame
        data=pd.read_csv(os.path.join(video_jpgs_path,'n_frames'),delimiter=' ',header=None)
        frame_count=data[0][0]
        video_x=np.zeros((16,240,320,3))

        image_start=random.randint(1,frame_count-17)
        image_id=image_start
        for i in range(16):
            s="%05d" % image_id
            image_name='image_'+s+'.jpg'
            image_path=os.path.join(video_jpgs_path,image_name)
            tmp_image = io.imread(image_path)
            video_x[i,:,:,:]=tmp_image
            image_id+=1
        return video_x





if __name__=='__main__':
    #usage
    root_list='/home/hl/Desktop/lovelyqian/CV_Learning/UCF101_jpg/'
    info_list='/home/hl/Desktop/lovelyqian/CV_Learning/UCF101_TrainTestlist/trainlist01.txt'
    myUCF101=UCF101(info_list,root_list,transform=transforms.Compose([ClipSubstractMean(),Rescale(),RandomCrop(),ToTensor()]))

    dataloader=DataLoader(myUCF101,batch_size=8,shuffle=True,num_workers=8)
    for i_batch,sample_batched in enumerate(dataloader):
        print (i_batch,sample_batched['video_x'].size(),sample_batched['video_label'].size())
  

整個(gè)代碼不管是在邏輯清晰度還是代碼行數(shù)上都比之前的改進(jìn)了很多捻爷,所以還是要多多學(xué)習(xí)大佬的框架,當(dāng)然能自己實(shí)現(xiàn)一遍也是挺好的啦份企。

參考文獻(xiàn)

視頻數(shù)據(jù)集UCF101的處理與加載(未使用深度學(xué)習(xí)框架)
PyTorch入門學(xué)習(xí)(七):數(shù)據(jù)加載與處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末也榄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子司志,更是在濱河造成了極大的恐慌甜紫,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骂远,死亡現(xiàn)場(chǎng)離奇詭異囚霸,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)激才,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門拓型,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人瘸恼,你說(shuō)我怎么就攤上這事劣挫。” “怎么了钞脂?”我有些...
    開封第一講書人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵揣云,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我冰啃,道長(zhǎng)邓夕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任阎毅,我火速辦了婚禮焚刚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扇调。我一直安慰自己矿咕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著碳柱,像睡著了一般捡絮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上莲镣,一...
    開封第一講書人閱讀 49,741評(píng)論 1 289
  • 那天福稳,我揣著相機(jī)與錄音,去河邊找鬼瑞侮。 笑死的圆,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的半火。 我是一名探鬼主播越妈,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钮糖!你這毒婦竟也來(lái)了梅掠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤藐鹤,失蹤者是張志新(化名)和其女友劉穎瓤檐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娱节,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挠蛉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肄满。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谴古。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稠歉,靈堂內(nèi)的尸體忽然破棺而出掰担,到底是詐尸還是另有隱情,我是刑警寧澤怒炸,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布带饱,位于F島的核電站,受9級(jí)特大地震影響阅羹,放射性物質(zhì)發(fā)生泄漏勺疼。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一捏鱼、第九天 我趴在偏房一處隱蔽的房頂上張望执庐。 院中可真熱鬧,春花似錦导梆、人聲如沸轨淌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)递鹉。三九已至盟步,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間躏结,已是汗流浹背址芯。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窜觉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓北专,卻偏偏與公主長(zhǎng)得像禀挫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拓颓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容