2024-03-15 15:00:46 +01:00
|
|
|
import csv
|
|
|
|
|
import os
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
import torch
|
|
|
|
|
import torchvision
|
|
|
|
|
import torchvision.transforms as transforms
|
|
|
|
|
from torchvision.datasets.folder import IMG_EXTENSIONS, pil_loader
|
|
|
|
|
|
|
|
|
|
from . import video_transforms
|
|
|
|
|
from .utils import center_crop_arr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_transforms_video(resolution=256):
|
|
|
|
|
transform_video = transforms.Compose(
|
|
|
|
|
[
|
|
|
|
|
video_transforms.ToTensorVideo(), # TCHW
|
|
|
|
|
video_transforms.RandomHorizontalFlipVideo(),
|
|
|
|
|
video_transforms.UCFCenterCropVideo(resolution),
|
|
|
|
|
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
return transform_video
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_transforms_image(image_size=256):
|
|
|
|
|
transform = transforms.Compose(
|
|
|
|
|
[
|
|
|
|
|
transforms.Lambda(lambda pil_image: center_crop_arr(pil_image, image_size)),
|
|
|
|
|
transforms.RandomHorizontalFlip(),
|
|
|
|
|
transforms.ToTensor(),
|
|
|
|
|
transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5], inplace=True),
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
return transform
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class DatasetFromCSV(torch.utils.data.Dataset):
|
|
|
|
|
"""load video according to the csv file.
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
target_video_len (int): the number of video frames will be load.
|
|
|
|
|
align_transform (callable): Align different videos in a specified size.
|
|
|
|
|
temporal_sample (callable): Sample the target length of a video.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
self,
|
|
|
|
|
csv_path,
|
|
|
|
|
num_frames=16,
|
|
|
|
|
frame_interval=1,
|
|
|
|
|
transform=None,
|
|
|
|
|
root=None,
|
|
|
|
|
):
|
|
|
|
|
self.csv_path = csv_path
|
|
|
|
|
with open(csv_path, "r") as f:
|
|
|
|
|
reader = csv.reader(f)
|
|
|
|
|
self.samples = list(reader)
|
|
|
|
|
|
|
|
|
|
ext = self.samples[0][0].split(".")[-1]
|
2024-03-17 08:47:48 +01:00
|
|
|
if ext.lower() in ("mp4", "avi", "mov", "mkv"):
|
2024-03-15 15:00:46 +01:00
|
|
|
self.is_video = True
|
|
|
|
|
else:
|
2024-03-16 14:17:16 +01:00
|
|
|
assert f".{ext.lower()}" in IMG_EXTENSIONS, f"Unsupported file format: {ext}"
|
2024-03-15 15:00:46 +01:00
|
|
|
self.is_video = False
|
|
|
|
|
|
|
|
|
|
self.transform = transform
|
|
|
|
|
|
|
|
|
|
self.num_frames = num_frames
|
|
|
|
|
self.frame_interval = frame_interval
|
|
|
|
|
self.temporal_sample = video_transforms.TemporalRandomCrop(num_frames * frame_interval)
|
|
|
|
|
self.root = root
|
|
|
|
|
|
|
|
|
|
def getitem(self, index):
|
|
|
|
|
sample = self.samples[index]
|
|
|
|
|
path = sample[0]
|
|
|
|
|
if self.root:
|
|
|
|
|
path = os.path.join(self.root, path)
|
|
|
|
|
text = sample[1]
|
|
|
|
|
|
|
|
|
|
if self.is_video:
|
|
|
|
|
vframes, aframes, info = torchvision.io.read_video(filename=path, pts_unit="sec", output_format="TCHW")
|
|
|
|
|
total_frames = len(vframes)
|
|
|
|
|
|
|
|
|
|
# Sampling video frames
|
|
|
|
|
start_frame_ind, end_frame_ind = self.temporal_sample(total_frames)
|
|
|
|
|
assert (
|
|
|
|
|
end_frame_ind - start_frame_ind >= self.num_frames
|
|
|
|
|
), f"{path} with index {index} has not enough frames."
|
|
|
|
|
frame_indice = np.linspace(start_frame_ind, end_frame_ind - 1, self.num_frames, dtype=int)
|
|
|
|
|
|
|
|
|
|
video = vframes[frame_indice]
|
|
|
|
|
video = self.transform(video) # T C H W
|
|
|
|
|
else:
|
|
|
|
|
image = pil_loader(path)
|
|
|
|
|
image = self.transform(image)
|
|
|
|
|
video = image.unsqueeze(0).repeat(self.num_frames, 1, 1, 1)
|
|
|
|
|
|
|
|
|
|
# TCHW -> CTHW
|
|
|
|
|
video = video.permute(1, 0, 2, 3)
|
|
|
|
|
|
|
|
|
|
return {"video": video, "text": text}
|
|
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
try:
|
|
|
|
|
return self.getitem(index)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
print(e)
|
|
|
|
|
index = np.random.randint(len(self))
|
|
|
|
|
raise RuntimeError("Too many bad data.")
|
|
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
|
return len(self.samples)
|