CoolFace
Apppublic

DFAGWE/infinitetalk2

sourceHugging Faceapache-2.0updated 8mo agoView on Hugging Face
0likes
vace_processor.py306 linesDownload Raw Back to utils
1# Copyright 2024-2025 The Alibaba Wan Team Authors. All rights reserved.2import numpy as np3import torch4import torch.nn.functional as F5import torchvision.transforms.functional as TF6from PIL import Image7 8 9class VaceImageProcessor(object):10 11    def __init__(self, downsample=None, seq_len=None):12        self.downsample = downsample13        self.seq_len = seq_len14 15    def _pillow_convert(self, image, cvt_type='RGB'):16        if image.mode != cvt_type:17            if image.mode == 'P':18                image = image.convert(f'{cvt_type}A')19            if image.mode == f'{cvt_type}A':20                bg = Image.new(21                    cvt_type,22                    size=(image.width, image.height),23                    color=(255, 255, 255))24                bg.paste(image, (0, 0), mask=image)25                image = bg26            else:27                image = image.convert(cvt_type)28        return image29 30    def _load_image(self, img_path):31        if img_path is None or img_path == '':32            return None33        img = Image.open(img_path)34        img = self._pillow_convert(img)35        return img36 37    def _resize_crop(self, img, oh, ow, normalize=True):38        """39        Resize, center crop, convert to tensor, and normalize.40        """41        # resize and crop42        iw, ih = img.size43        if iw != ow or ih != oh:44            # resize45            scale = max(ow / iw, oh / ih)46            img = img.resize((round(scale * iw), round(scale * ih)),47                             resample=Image.Resampling.LANCZOS)48            assert img.width >= ow and img.height >= oh49 50            # center crop51            x1 = (img.width - ow) // 252            y1 = (img.height - oh) // 253            img = img.crop((x1, y1, x1 + ow, y1 + oh))54 55        # normalize56        if normalize:57            img = TF.to_tensor(img).sub_(0.5).div_(0.5).unsqueeze(1)58        return img59 60    def _image_preprocess(self, img, oh, ow, normalize=True, **kwargs):61        return self._resize_crop(img, oh, ow, normalize)62 63    def load_image(self, data_key, **kwargs):64        return self.load_image_batch(data_key, **kwargs)65 66    def load_image_pair(self, data_key, data_key2, **kwargs):67        return self.load_image_batch(data_key, data_key2, **kwargs)68 69    def load_image_batch(self,70                         *data_key_batch,71                         normalize=True,72                         seq_len=None,73                         **kwargs):74        seq_len = self.seq_len if seq_len is None else seq_len75        imgs = []76        for data_key in data_key_batch:77            img = self._load_image(data_key)78            imgs.append(img)79        w, h = imgs[0].size80        dh, dw = self.downsample[1:]81 82        # compute output size83        scale = min(1., np.sqrt(seq_len / ((h / dh) * (w / dw))))84        oh = int(h * scale) // dh * dh85        ow = int(w * scale) // dw * dw86        assert (oh // dh) * (ow // dw) <= seq_len87        imgs = [self._image_preprocess(img, oh, ow, normalize) for img in imgs]88        return *imgs, (oh, ow)89 90 91class VaceVideoProcessor(object):92 93    def __init__(self, downsample, min_area, max_area, min_fps, max_fps,94                 zero_start, seq_len, keep_last, **kwargs):95        self.downsample = downsample96        self.min_area = min_area97        self.max_area = max_area98        self.min_fps = min_fps99        self.max_fps = max_fps100        self.zero_start = zero_start101        self.keep_last = keep_last102        self.seq_len = seq_len103        assert seq_len >= min_area / (self.downsample[1] * self.downsample[2])104 105    def set_area(self, area):106        self.min_area = area107        self.max_area = area108 109    def set_seq_len(self, seq_len):110        self.seq_len = seq_len111 112    @staticmethod113    def resize_crop(video: torch.Tensor, oh: int, ow: int):114        """115        Resize, center crop and normalize for decord loaded video (torch.Tensor type)116 117        Parameters:118          video - video to process (torch.Tensor): Tensor from `reader.get_batch(frame_ids)`, in shape of (T, H, W, C)119          oh - target height (int)120          ow - target width (int)121 122        Returns:123            The processed video (torch.Tensor): Normalized tensor range [-1, 1], in shape of (C, T, H, W)124 125        Raises:126        """127        # permute ([t, h, w, c] -> [t, c, h, w])128        video = video.permute(0, 3, 1, 2)129 130        # resize and crop131        ih, iw = video.shape[2:]132        if ih != oh or iw != ow:133            # resize134            scale = max(ow / iw, oh / ih)135            video = F.interpolate(136                video,137                size=(round(scale * ih), round(scale * iw)),138                mode='bicubic',139                antialias=True)140            assert video.size(3) >= ow and video.size(2) >= oh141 142            # center crop143            x1 = (video.size(3) - ow) // 2144            y1 = (video.size(2) - oh) // 2145            video = video[:, :, y1:y1 + oh, x1:x1 + ow]146 147        # permute ([t, c, h, w] -> [c, t, h, w]) and normalize148        video = video.transpose(0, 1).float().div_(127.5).sub_(1.)149        return video150 151    def _video_preprocess(self, video, oh, ow):152        return self.resize_crop(video, oh, ow)153 154    def _get_frameid_bbox_default(self, fps, frame_timestamps, h, w, crop_box,155                                  rng):156        target_fps = min(fps, self.max_fps)157        duration = frame_timestamps[-1].mean()158        x1, x2, y1, y2 = [0, w, 0, h] if crop_box is None else crop_box159        h, w = y2 - y1, x2 - x1160        ratio = h / w161        df, dh, dw = self.downsample162 163        area_z = min(self.seq_len, self.max_area / (dh * dw),164                     (h // dh) * (w // dw))165        of = min((int(duration * target_fps) - 1) // df + 1,166                 int(self.seq_len / area_z))167 168        # deduce target shape of the [latent video]169        target_area_z = min(area_z, int(self.seq_len / of))170        oh = round(np.sqrt(target_area_z * ratio))171        ow = int(target_area_z / oh)172        of = (of - 1) * df + 1173        oh *= dh174        ow *= dw175 176        # sample frame ids177        target_duration = of / target_fps178        begin = 0. if self.zero_start else rng.uniform(179            0, duration - target_duration)180        timestamps = np.linspace(begin, begin + target_duration, of)181        frame_ids = np.argmax(182            np.logical_and(timestamps[:, None] >= frame_timestamps[None, :, 0],183                           timestamps[:, None] < frame_timestamps[None, :, 1]),184            axis=1).tolist()185        return frame_ids, (x1, x2, y1, y2), (oh, ow), target_fps186 187    def _get_frameid_bbox_adjust_last(self, fps, frame_timestamps, h, w,188                                      crop_box, rng):189        duration = frame_timestamps[-1].mean()190        x1, x2, y1, y2 = [0, w, 0, h] if crop_box is None else crop_box191        h, w = y2 - y1, x2 - x1192        ratio = h / w193        df, dh, dw = self.downsample194 195        area_z = min(self.seq_len, self.max_area / (dh * dw),196                     (h // dh) * (w // dw))197        of = min((len(frame_timestamps) - 1) // df + 1,198                 int(self.seq_len / area_z))199 200        # deduce target shape of the [latent video]201        target_area_z = min(area_z, int(self.seq_len / of))202        oh = round(np.sqrt(target_area_z * ratio))203        ow = int(target_area_z / oh)204        of = (of - 1) * df + 1205        oh *= dh206        ow *= dw207 208        # sample frame ids209        target_duration = duration210        target_fps = of / target_duration211        timestamps = np.linspace(0., target_duration, of)212        frame_ids = np.argmax(213            np.logical_and(timestamps[:, None] >= frame_timestamps[None, :, 0],214                           timestamps[:, None] <= frame_timestamps[None, :, 1]),215            axis=1).tolist()216        # print(oh, ow, of, target_duration, target_fps, len(frame_timestamps), len(frame_ids))217        return frame_ids, (x1, x2, y1, y2), (oh, ow), target_fps218 219    def _get_frameid_bbox(self, fps, frame_timestamps, h, w, crop_box, rng):220        if self.keep_last:221            return self._get_frameid_bbox_adjust_last(fps, frame_timestamps, h,222                                                      w, crop_box, rng)223        else:224            return self._get_frameid_bbox_default(fps, frame_timestamps, h, w,225                                                  crop_box, rng)226 227    def load_video(self, data_key, crop_box=None, seed=2024, **kwargs):228        return self.load_video_batch(229            data_key, crop_box=crop_box, seed=seed, **kwargs)230 231    def load_video_pair(self,232                        data_key,233                        data_key2,234                        crop_box=None,235                        seed=2024,236                        **kwargs):237        return self.load_video_batch(238            data_key, data_key2, crop_box=crop_box, seed=seed, **kwargs)239 240    def load_video_batch(self,241                         *data_key_batch,242                         crop_box=None,243                         seed=2024,244                         **kwargs):245        rng = np.random.default_rng(seed + hash(data_key_batch[0]) % 10000)246        # read video247        import decord248        decord.bridge.set_bridge('torch')249        readers = []250        for data_k in data_key_batch:251            reader = decord.VideoReader(data_k)252            readers.append(reader)253 254        fps = readers[0].get_avg_fps()255        length = min([len(r) for r in readers])256        frame_timestamps = [257            readers[0].get_frame_timestamp(i) for i in range(length)258        ]259        frame_timestamps = np.array(frame_timestamps, dtype=np.float32)260        h, w = readers[0].next().shape[:2]261        frame_ids, (x1, x2, y1, y2), (oh, ow), fps = self._get_frameid_bbox(262            fps, frame_timestamps, h, w, crop_box, rng)263 264        # preprocess video265        videos = [266            reader.get_batch(frame_ids)[:, y1:y2, x1:x2, :]267            for reader in readers268        ]269        videos = [self._video_preprocess(video, oh, ow) for video in videos]270        return *videos, frame_ids, (oh, ow), fps271        # return videos if len(videos) > 1 else videos[0]272 273 274def prepare_source(src_video, src_mask, src_ref_images, num_frames, image_size,275                   device):276    for i, (sub_src_video, sub_src_mask) in enumerate(zip(src_video, src_mask)):277        if sub_src_video is None and sub_src_mask is None:278            src_video[i] = torch.zeros(279                (3, num_frames, image_size[0], image_size[1]), device=device)280            src_mask[i] = torch.ones(281                (1, num_frames, image_size[0], image_size[1]), device=device)282    for i, ref_images in enumerate(src_ref_images):283        if ref_images is not None:284            for j, ref_img in enumerate(ref_images):285                if ref_img is not None and ref_img.shape[-2:] != image_size:286                    canvas_height, canvas_width = image_size287                    ref_height, ref_width = ref_img.shape[-2:]288                    white_canvas = torch.ones(289                        (3, 1, canvas_height, canvas_width),290                        device=device)  # [-1, 1]291                    scale = min(canvas_height / ref_height,292                                canvas_width / ref_width)293                    new_height = int(ref_height * scale)294                    new_width = int(ref_width * scale)295                    resized_image = F.interpolate(296                        ref_img.squeeze(1).unsqueeze(0),297                        size=(new_height, new_width),298                        mode='bilinear',299                        align_corners=False).squeeze(0).unsqueeze(1)300                    top = (canvas_height - new_height) // 2301                    left = (canvas_width - new_width) // 2302                    white_canvas[:, :, top:top + new_height,303                                 left:left + new_width] = resized_image304                    src_ref_images[i][j] = white_canvas305    return src_video, src_mask, src_ref_images306