|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
import numpy as np |
|
from torch.utils.data import Dataset |
|
import torch |
|
import random |
|
import cv2 |
|
from ..utils.image_processor import ImageProcessor, load_fixed_mask |
|
from ..utils.audio import melspectrogram |
|
from decord import AudioReader, VideoReader, cpu |
|
|
|
|
|
class UNetDataset(Dataset): |
|
def __init__(self, train_data_dir: str, config): |
|
if config.data.train_fileslist != "": |
|
with open(config.data.train_fileslist) as file: |
|
self.video_paths = [line.rstrip() for line in file] |
|
elif train_data_dir != "": |
|
self.video_paths = [] |
|
for file in os.listdir(train_data_dir): |
|
if file.endswith(".mp4"): |
|
self.video_paths.append(os.path.join(train_data_dir, file)) |
|
else: |
|
raise ValueError("data_dir and fileslist cannot be both empty") |
|
|
|
self.resolution = config.data.resolution |
|
self.num_frames = config.data.num_frames |
|
|
|
if self.num_frames == 16: |
|
self.mel_window_length = 52 |
|
elif self.num_frames == 5: |
|
self.mel_window_length = 16 |
|
else: |
|
raise NotImplementedError("Only support 16 and 5 frames now") |
|
|
|
self.audio_sample_rate = config.data.audio_sample_rate |
|
self.video_fps = config.data.video_fps |
|
self.mask = config.data.mask |
|
self.mask_image = load_fixed_mask(self.resolution) |
|
self.load_audio_data = config.model.add_audio_layer and config.run.use_syncnet |
|
self.audio_mel_cache_dir = config.data.audio_mel_cache_dir |
|
os.makedirs(self.audio_mel_cache_dir, exist_ok=True) |
|
|
|
def __len__(self): |
|
return len(self.video_paths) |
|
|
|
def read_audio(self, video_path: str): |
|
ar = AudioReader(video_path, ctx=cpu(self.worker_id), sample_rate=self.audio_sample_rate) |
|
original_mel = melspectrogram(ar[:].asnumpy().squeeze(0)) |
|
return torch.from_numpy(original_mel) |
|
|
|
def crop_audio_window(self, original_mel, start_index): |
|
start_idx = int(80.0 * (start_index / float(self.video_fps))) |
|
end_idx = start_idx + self.mel_window_length |
|
return original_mel[:, start_idx:end_idx].unsqueeze(0) |
|
|
|
def get_frames(self, video_reader: VideoReader): |
|
total_num_frames = len(video_reader) |
|
|
|
start_idx = random.randint(self.num_frames // 2, total_num_frames - self.num_frames - self.num_frames // 2) |
|
frames_index = np.arange(start_idx, start_idx + self.num_frames, dtype=int) |
|
|
|
while True: |
|
wrong_start_idx = random.randint(0, total_num_frames - self.num_frames) |
|
if wrong_start_idx > start_idx - self.num_frames and wrong_start_idx < start_idx + self.num_frames: |
|
continue |
|
wrong_frames_index = np.arange(wrong_start_idx, wrong_start_idx + self.num_frames, dtype=int) |
|
break |
|
|
|
frames = video_reader.get_batch(frames_index).asnumpy() |
|
wrong_frames = video_reader.get_batch(wrong_frames_index).asnumpy() |
|
|
|
return frames, wrong_frames, start_idx |
|
|
|
def worker_init_fn(self, worker_id): |
|
|
|
|
|
self.worker_id = worker_id |
|
setattr( |
|
self, |
|
f"image_processor_{worker_id}", |
|
ImageProcessor(self.resolution, self.mask, mask_image=self.mask_image), |
|
) |
|
|
|
def __getitem__(self, idx): |
|
image_processor = getattr(self, f"image_processor_{self.worker_id}") |
|
while True: |
|
try: |
|
idx = random.randint(0, len(self) - 1) |
|
|
|
|
|
video_path = self.video_paths[idx] |
|
|
|
vr = VideoReader(video_path, ctx=cpu(self.worker_id)) |
|
|
|
if len(vr) < 3 * self.num_frames: |
|
continue |
|
|
|
continuous_frames, ref_frames, start_idx = self.get_frames(vr) |
|
|
|
if self.load_audio_data: |
|
mel_cache_path = os.path.join( |
|
self.audio_mel_cache_dir, os.path.basename(video_path).replace(".mp4", "_mel.pt") |
|
) |
|
|
|
if os.path.isfile(mel_cache_path): |
|
try: |
|
original_mel = torch.load(mel_cache_path) |
|
except Exception as e: |
|
print(f"{type(e).__name__} - {e} - {mel_cache_path}") |
|
os.remove(mel_cache_path) |
|
original_mel = self.read_audio(video_path) |
|
torch.save(original_mel, mel_cache_path) |
|
else: |
|
original_mel = self.read_audio(video_path) |
|
torch.save(original_mel, mel_cache_path) |
|
|
|
mel = self.crop_audio_window(original_mel, start_idx) |
|
|
|
if mel.shape[-1] != self.mel_window_length: |
|
continue |
|
else: |
|
mel = [] |
|
|
|
gt, masked_gt, mask = image_processor.prepare_masks_and_masked_images( |
|
continuous_frames, affine_transform=False |
|
) |
|
|
|
if self.mask == "fix_mask": |
|
ref, _, _ = image_processor.prepare_masks_and_masked_images(ref_frames, affine_transform=False) |
|
else: |
|
ref = image_processor.process_images(ref_frames) |
|
vr.seek(0) |
|
break |
|
|
|
except Exception as e: |
|
print(f"{type(e).__name__} - {e} - {video_path}") |
|
if "vr" in locals(): |
|
vr.seek(0) |
|
|
|
sample = dict( |
|
gt=gt, |
|
masked_gt=masked_gt, |
|
ref=ref, |
|
mel=mel, |
|
mask=mask, |
|
video_path=video_path, |
|
start_idx=start_idx, |
|
) |
|
|
|
return sample |
|
|