| import os |
| import random |
| import torch |
| from torch.utils.data import Dataset |
| from decord import VideoReader, cpu |
| import pandas as pd |
|
|
|
|
| class DatasetVideoLoader(Dataset): |
| """ |
| Dataset for loading videos and captions from a CSV file. |
| CSV file contains two columns: 'path' and 'text', where: |
| - 'path' is the path to the video file |
| - 'text' is the caption for the video. |
| """ |
|
|
| def __init__( |
| self, |
| csv_file, |
| resolution, |
| video_length, |
| frame_stride=4, |
| subset_split="all", |
| clip_length=1.0, |
| random_stride=False, |
| mode="video", |
| ): |
| self.csv_file = csv_file |
| self.resolution = resolution |
| self.video_length = video_length |
| self.subset_split = subset_split |
| self.frame_stride = frame_stride |
| self.clip_length = clip_length |
| self.random_stride = random_stride |
| self.mode = mode |
|
|
| assert self.subset_split in ["train", "test", "val", "all"] |
| self.exts = ["avi", "mp4", "webm"] |
|
|
| if isinstance(self.resolution, int): |
| self.resolution = [self.resolution, self.resolution] |
|
|
| |
| self._make_dataset() |
|
|
| def _make_dataset(self): |
| """ |
| Load video paths and captions from the CSV file. |
| """ |
| self.videos = pd.read_csv(self.csv_file) |
| print(f"Loaded {len(self.videos)} videos from {self.csv_file}") |
|
|
| if self.subset_split == "val": |
| self.videos = self.videos[-300:] |
| elif self.subset_split == "train": |
| self.videos = self.videos[:-300] |
| elif self.subset_split == "test": |
| self.videos = self.videos[-30:] |
|
|
| print(f"Number of videos = {len(self.videos)}") |
|
|
| |
| self.video_indices = list(range(len(self.videos))) |
|
|
| def set_mode(self, mode): |
| self.mode = mode |
|
|
| def _get_video_path(self, index): |
| return self.videos.iloc[index]["path"] |
|
|
| def __getitem__(self, index): |
| if self.mode == "image": |
| return self.__getitem__images(index) |
| else: |
| return self.__getitem__video(index) |
|
|
| def __getitem__video(self, index): |
| while True: |
| video_path = self.videos.iloc[index]["path"] |
| caption = self.videos.iloc[index]["text"] |
|
|
| try: |
| video_reader = VideoReader( |
| video_path, |
| ctx=cpu(0), |
| width=self.resolution[1], |
| height=self.resolution[0], |
| ) |
| if len(video_reader) < self.video_length: |
| index = (index + 1) % len(self.videos) |
| continue |
| else: |
| break |
| except Exception as e: |
| print(f"Load video failed! path = {video_path}, error: {str(e)}") |
| index = (index + 1) % len(self.videos) |
| continue |
|
|
| if self.random_stride: |
| self.frame_stride = random.choice([4, 8, 12, 16]) |
|
|
| all_frames = list(range(0, len(video_reader), self.frame_stride)) |
| if len(all_frames) < self.video_length: |
| all_frames = list(range(0, len(video_reader), 1)) |
|
|
| |
| rand_idx = random.randint(0, len(all_frames) - self.video_length) |
| frame_indices = all_frames[rand_idx : rand_idx + self.video_length] |
| frames = video_reader.get_batch(frame_indices) |
| assert ( |
| frames.shape[0] == self.video_length |
| ), f"{len(frames)}, self.video_length={self.video_length}" |
|
|
| frames = ( |
| torch.tensor(frames.asnumpy()).permute(3, 0, 1, 2).float() |
| ) |
| assert ( |
| frames.shape[2] == self.resolution[0] |
| and frames.shape[3] == self.resolution[1] |
| ), f"frames={frames.shape}, self.resolution={self.resolution}" |
| frames = (frames / 255 - 0.5) * 2 |
|
|
| return {"video": frames, "caption": caption, "is_video": True} |
|
|
| def __getitem__images(self, index): |
| frames_list = [] |
| for i in range(self.video_length): |
| |
| video_index = (index + i) % len(self.video_indices) |
| video_path = self._get_video_path(video_index) |
|
|
| try: |
| video_reader = VideoReader( |
| video_path, |
| ctx=cpu(0), |
| width=self.resolution[1], |
| height=self.resolution[0], |
| ) |
| except Exception as e: |
| print(f"Load video failed! path = {video_path}, error = {e}") |
| |
| return self.__getitem__images((index + 1) % len(self.video_indices)) |
|
|
| |
| rand_idx = random.randint(0, len(video_reader) - 1) |
| frame = video_reader[rand_idx] |
| frame_tensor = ( |
| torch.tensor(frame.asnumpy()).permute(2, 0, 1).float().unsqueeze(0) |
| ) |
|
|
| frames_list.append(frame_tensor) |
|
|
| frames = torch.cat(frames_list, dim=0) |
| frames = (frames / 255 - 0.5) * 2 |
| frames = frames.permute(1, 0, 2, 3) |
| assert ( |
| frames.shape[2] == self.resolution[0] |
| and frames.shape[3] == self.resolution[1] |
| ), f"frame={frames.shape}, self.resolution={self.resolution}" |
|
|
| data = {"video": frames, "is_video": False} |
| return data |
|
|
| def __len__(self): |
| return len(self.videos) |
|
|