| from typing import * |
| from abc import abstractmethod |
| import os |
| import json |
| import torch |
| import numpy as np |
| import pandas as pd |
| from PIL import Image |
| from torch.utils.data import Dataset |
| import json |
| import random |
| import math |
| import rembg |
| import copy |
| from pathlib import Path |
|
|
|
|
|
|
|
|
| def _editverse_clean_encoded_base(clean_root: str, key: str, *, is_alpaca: bool) -> Path: |
| """Root directory for one sample under 3Deditverse_data/encoded_ouput/.""" |
| sub = "alpaca_encode" if is_alpaca else "flux_encode" |
| return Path(clean_root) / "encoded_ouput" / sub / key |
|
|
|
|
| def preprocess_condition_image(image: Image.Image, image_size: int, rembg_session=None, aug_bbox=None): |
| """Preprocess editing condition images shared by 3DEditVerse and H3D.""" |
| if np.array(image).shape[-1] != 4: |
| if rembg_session is None: |
| rembg_session = rembg.new_session('u2net') |
| image = rembg.remove(image, session=rembg_session) |
|
|
| alpha = np.array(image.getchannel(3)) |
| if aug_bbox is None: |
| bbox = np.array(alpha).nonzero() |
| bbox = [bbox[1].min(), bbox[0].min(), bbox[1].max(), bbox[0].max()] |
| center = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2] |
| hsize = max(bbox[2] - bbox[0], bbox[3] - bbox[1]) / 2 |
| aug_size_ratio = 1.2 |
| aug_hsize = hsize * aug_size_ratio |
| aug_center_offset = [0, 0] |
| aug_center = [center[0] + aug_center_offset[0], center[1] + aug_center_offset[1]] |
| aug_bbox = [ |
| int(aug_center[0] - aug_hsize), |
| int(aug_center[1] - aug_hsize), |
| int(aug_center[0] + aug_hsize), |
| int(aug_center[1] + aug_hsize), |
| ] |
|
|
| image = image.crop(aug_bbox) |
| image = image.resize((image_size, image_size), Image.Resampling.LANCZOS) |
| alpha = image.getchannel(3) |
| image = image.convert('RGB') |
| image = torch.tensor(np.array(image)).permute(2, 0, 1).float() / 255.0 |
| alpha = torch.tensor(np.array(alpha)).float() / 255.0 |
| image = image * alpha.unsqueeze(0) |
| return image, aug_bbox, rembg_session |
|
|
|
|
| class EditingStandardDatasetBase(Dataset): |
| """ |
| Base class for standard datasets. |
| |
| Args: |
| roots (str): paths to the dataset |
| """ |
|
|
| def __init__(self, |
| roots: str, |
| json_file: str, |
| dataset_num: Optional[int] = None, |
| random_cond_gt: bool = False, |
| |
| mixamo_data_repeat_ratio: float = 2.0, |
| |
| |
| |
| |
| |
| |
| |
| |
| adapt_simple_edit_data: bool = False, |
| load_data_type: str = 'ss_latents', |
| |
| mixamo_root_path: Optional[str] = None, |
| flux_edit_root_path: Optional[str] = None, |
| alpaca_root_path: Optional[str] = None, |
| dataset_info_path: Optional[str] = None, |
| alpaca_confidence_json_path: Optional[str] = None, |
| flux_edit_confidence_json_path: Optional[str] = None, |
| filter_info: Optional[dict] = None, |
| random_ori_edit: Optional[float] = None, |
| flux_edit_alpaca_test_json_path: Optional[str] = None, |
| mixamo_test_animation: Optional[List[str]] = None, |
| simple_edit_data_if_filtered: bool = False, |
| include_mixamo: bool = True, |
| include_flux_edit: bool = True, |
| include_alpaca: bool = True, |
| max_samples: Optional[int] = None, |
| editverse_clean_root: Optional[str] = None, |
| ): |
| super().__init__() |
| self.roots = roots |
| self.json_file = json_file |
| self.dataset_num = dataset_num |
| self.random_cond_gt = random_cond_gt |
| |
| self.mixamo_data_repeat_ratio = mixamo_data_repeat_ratio |
| |
| |
| |
| |
| |
| |
| |
| |
| self.adapt_simple_edit_data = adapt_simple_edit_data |
| self.load_data_type = load_data_type |
| |
| self.mixamo_root_path = mixamo_root_path |
| self.flux_edit_root_path = flux_edit_root_path |
| self.alpaca_root_path = alpaca_root_path |
| self.dataset_info_path = dataset_info_path |
| self.alpaca_confidence_json_path = alpaca_confidence_json_path |
| self.flux_edit_confidence_json_path = flux_edit_confidence_json_path |
| self.filter_info = filter_info |
| self.random_ori_edit = random_ori_edit |
| self.flux_edit_alpaca_test_json_path = flux_edit_alpaca_test_json_path |
| self.mixamo_test_animation = mixamo_test_animation |
| self.simple_edit_data_if_filtered = simple_edit_data_if_filtered |
| self.include_mixamo = include_mixamo |
| self.include_flux_edit = include_flux_edit |
| self.include_alpaca = include_alpaca |
| self.max_samples = max_samples |
| self.editverse_clean_root = ( |
| os.path.abspath(os.path.expanduser(editverse_clean_root)) |
| if editverse_clean_root is not None |
| else None |
| ) |
| if self.editverse_clean_root is not None: |
| if adapt_simple_edit_data: |
| raise ValueError( |
| "adapt_simple_edit_data is incompatible with editverse_clean_root " |
| "(clean encoded tree has no simple_edit_ss paths)." |
| ) |
| if simple_edit_data_if_filtered: |
| raise ValueError( |
| "simple_edit_data_if_filtered is incompatible with editverse_clean_root." |
| ) |
| assert self.load_data_type in ['ss_latents', 'latents'], f'Invalid load_data_type: {self.load_data_type}' |
| if self.filter_info is not None: |
| with open(self.flux_edit_confidence_json_path, 'r') as f: |
| self.flux_edit_confidence_json = json.load(f) |
| with open(self.alpaca_confidence_json_path, 'r') as f: |
| self.alpaca_confidence_json = json.load(f) |
| with open(self.dataset_info_path, 'r') as f: |
| self.dataset_info = json.load(f) |
| if self.random_ori_edit is not None: |
| assert self.load_data_type == 'ss_latents', f'Invalid load_data_type: {self.load_data_type}' |
| if self.flux_edit_alpaca_test_json_path is not None: |
| with open(self.flux_edit_alpaca_test_json_path, 'r') as f: |
| self.flux_edit_alpaca_test_json = json.load(f) |
| self.flux_edit_alpaca_test_json = self.flux_edit_alpaca_test_json['alpaca'] + self.flux_edit_alpaca_test_json['flux_edit'] |
| assert isinstance(self.flux_edit_alpaca_test_json, list) |
| test_num = len(self.flux_edit_alpaca_test_json) |
| self.flux_edit_alpaca_test_json = set(self.flux_edit_alpaca_test_json) |
| assert test_num == len(self.flux_edit_alpaca_test_json) |
|
|
| |
| |
| self.voxel_loads = [] |
| |
| self.mixamo_instances = self.dataset_info['mixamo'] if self.include_mixamo else {} |
| print('Ori mixamo data num: ', sum(len(instances) for instances in self.mixamo_instances.values())) |
| _mixamo_instances = [] |
| for character_name, instances in self.mixamo_instances.items(): |
| if self.mixamo_test_animation is not None and character_name in self.mixamo_test_animation: |
| continue |
| object_num = 0 |
| for _ in range(math.ceil(self.mixamo_data_repeat_ratio)): |
| random.shuffle(instances) |
| i, j = 0, len(instances) - 1 |
| while i < j: |
| _mixamo_instances.append([ |
| os.path.join(self.mixamo_root_path, instances[i]['ss_latents_path' if self.load_data_type == 'ss_latents' else 'latents_path']), |
| os.path.join(self.mixamo_root_path, instances[j]['ss_latents_path' if self.load_data_type == 'ss_latents' else 'latents_path']), |
| os.path.join(self.mixamo_root_path, instances[i]['img_path']), |
| os.path.join(self.mixamo_root_path, instances[j]['img_path']), |
| ]) |
| self.voxel_loads.append((instances[i]['voxel_num'] + instances[j]['voxel_num']) // 2) |
| object_num += 1 |
| i += 1 |
| j -= 1 |
| if object_num >= len(instances) * self.mixamo_data_repeat_ratio: |
| break |
| self.mixamo_instances = _mixamo_instances |
| print(f'Repeated Mixamo data num: {len(self.mixamo_instances)}') |
|
|
| |
| self.flux_editing_instances = [] |
| remove_num = 0 |
| test_num = 0 |
| for key, value in (self.dataset_info['flux_edit'] if self.include_flux_edit else {}).items(): |
|
|
| |
| ori_ss_latents_path = value['ori_ss_latents_path' if self.load_data_type == 'ss_latents' else 'ori_latents_path'] |
| edited_ss_latents_path = value['edit_ss_latents_path' if self.load_data_type == 'ss_latents' else 'edit_latents_path'] |
|
|
| |
| if self.flux_edit_alpaca_test_json_path is not None and key in self.flux_edit_alpaca_test_json: |
| test_num += 1 |
| continue |
|
|
| |
| if self.filter_info is not None: |
| choose_flag = True |
| for filter_key, filter_range in filter_info.items(): |
| min_val, max_val = filter_range |
| if self.flux_edit_confidence_json[key][filter_key] < min_val or self.flux_edit_confidence_json[key][filter_key] > max_val: |
| choose_flag = False |
| break |
| if not choose_flag: |
| if not self.simple_edit_data_if_filtered: |
| remove_num += 1 |
| continue |
| else: |
| assert self.load_data_type == 'ss_latents' |
| edited_ss_latents_path = edited_ss_latents_path.replace('edit_ss', 'simple_edit_ss').replace('data_v4', 'data_v2') |
| assert os.path.exists(os.path.join(self.flux_edit_root_path, edited_ss_latents_path)), f'{edited_ss_latents_path} not found' |
| |
| |
| if self.editverse_clean_root is None: |
| if self.adapt_simple_edit_data: |
| assert self.load_data_type == 'ss_latents' |
| edited_ss_latents_path = edited_ss_latents_path.replace('edit_ss', 'simple_edit_ss').replace('data_v4', 'data_v2') |
| assert os.path.exists(os.path.join(self.flux_edit_root_path, edited_ss_latents_path)), f'{edited_ss_latents_path} not found' |
| self.flux_editing_instances.append([ |
| os.path.join(self.flux_edit_root_path, ori_ss_latents_path), |
| os.path.join(self.flux_edit_root_path, edited_ss_latents_path), |
| os.path.join(self.flux_edit_root_path, value['ori_img_path']), |
| os.path.join(self.flux_edit_root_path, value['edit_img_path']), |
| ]) |
| else: |
| ori_latent, edit_latent = self._editverse_clean_latent_pair(key, is_alpaca=False) |
| ori_img, edit_img = self._editverse_clean_cond_image_pair(key, value, is_alpaca=False) |
| if not (os.path.isfile(ori_latent) and os.path.isfile(edit_latent)): |
| remove_num += 1 |
| continue |
| if not (os.path.isfile(ori_img) and os.path.isfile(edit_img)): |
| remove_num += 1 |
| continue |
| self.flux_editing_instances.append([ |
| ori_latent, |
| edit_latent, |
| ori_img, |
| edit_img, |
| ]) |
| self.voxel_loads.append((value['ori_voxel_num'] + value['edit_voxel_num']) // 2) |
| print(f'Remove flux editing data (based on confidence) num: {remove_num}') |
| print(f'Remove test flux editing data num: {test_num}') |
| print(f'Flux editing data num: {len(self.flux_editing_instances)}') |
|
|
| |
| self.alpaca_editing_instances = [] |
| remove_num = 0 |
| test_num = 0 |
| for key, value in (self.dataset_info['alpaca'] if self.include_alpaca else {}).items(): |
|
|
| |
| ori_ss_latents_path = value['ori_ss_latents_path' if self.load_data_type == 'ss_latents' else 'ori_latents_path'] |
| edited_ss_latents_path = value['edit_ss_latents_path' if self.load_data_type == 'ss_latents' else 'edit_latents_path'] |
|
|
| |
| if self.flux_edit_alpaca_test_json_path is not None and key in self.flux_edit_alpaca_test_json: |
| test_num += 1 |
| continue |
|
|
| |
| if self.filter_info is not None: |
| choose_flag = True |
| for filter_key, filter_range in filter_info.items(): |
| min_val, max_val = filter_range |
| if self.alpaca_confidence_json[key][filter_key] < min_val or self.alpaca_confidence_json[key][filter_key] > max_val: |
| choose_flag = False |
| break |
| if not choose_flag: |
| if not self.simple_edit_data_if_filtered: |
| remove_num += 1 |
| continue |
| else: |
| assert self.load_data_type == 'ss_latents' |
| edited_ss_latents_path = edited_ss_latents_path.replace('edit_ss', 'simple_edit_ss').replace('data_V3', 'data_V2') |
| assert os.path.exists(os.path.join(self.alpaca_root_path, edited_ss_latents_path)), f'{edited_ss_latents_path} not found' |
| |
| |
| if self.editverse_clean_root is None: |
| if self.adapt_simple_edit_data: |
| assert self.load_data_type == 'ss_latents' |
| edited_ss_latents_path = edited_ss_latents_path.replace('edit_ss', 'simple_edit_ss').replace('data_V3', 'data_V2') |
| assert os.path.exists(os.path.join(self.alpaca_root_path, edited_ss_latents_path)), f'{edited_ss_latents_path} not found' |
| self.alpaca_editing_instances.append([ |
| os.path.join(self.alpaca_root_path, ori_ss_latents_path), |
| os.path.join(self.alpaca_root_path, edited_ss_latents_path), |
| os.path.join(self.alpaca_root_path, value['ori_img_path']), |
| os.path.join(self.alpaca_root_path, value['edit_img_path']), |
| ]) |
| else: |
| ori_latent, edit_latent = self._editverse_clean_latent_pair(key, is_alpaca=True) |
| ori_img, edit_img = self._editverse_clean_cond_image_pair(key, value, is_alpaca=True) |
| if not (os.path.isfile(ori_latent) and os.path.isfile(edit_latent)): |
| remove_num += 1 |
| continue |
| if not (os.path.isfile(ori_img) and os.path.isfile(edit_img)): |
| remove_num += 1 |
| continue |
| self.alpaca_editing_instances.append([ |
| ori_latent, |
| edit_latent, |
| ori_img, |
| edit_img, |
| ]) |
| self.voxel_loads.append((value['ori_voxel_num'] + value['edit_voxel_num']) // 2) |
| print(f'Remove alpaca editing data (based on confidence) num: {remove_num}') |
| print(f'Remove test alpaca editing data num: {test_num}') |
| print(f'Alpaca editing data num: {len(self.alpaca_editing_instances)}') |
|
|
| if self.max_samples is not None: |
| original_num = len(self.mixamo_instances) + len(self.flux_editing_instances) + len(self.alpaca_editing_instances) |
| remaining = self.max_samples |
| self.mixamo_instances = self.mixamo_instances[:remaining] |
| remaining -= len(self.mixamo_instances) |
| self.flux_editing_instances = self.flux_editing_instances[:max(0, remaining)] |
| remaining -= len(self.flux_editing_instances) |
| self.alpaca_editing_instances = self.alpaca_editing_instances[:max(0, remaining)] |
| self.voxel_loads = self.voxel_loads[:self.max_samples] |
| print(f'Limit editing data num from {original_num} to {len(self.mixamo_instances) + len(self.flux_editing_instances) + len(self.alpaca_editing_instances)}') |
|
|
| |
| '''# ---- load mixamo data |
| self.mixamo_instances = defaultdict(list) |
| if self.load_data_type == 'ss_latents': |
| self.mixamo_ss_latents_path = os.path.join(self.mixamo_data_path, 'ss_latents', 'ss_enc_conv3d_16l8_fp16') |
| else: |
| self.mixamo_ss_latents_path = os.path.join(self.mixamo_data_path, 'latents', 'dinov2_vitl14_reg_slat_enc_swin8_B_64l8_fp16') |
| self.mixamo_renders_cond_path = os.path.join(self.mixamo_data_path, 'renders_cond') |
| self.mixamo_ss_latents_list = os.listdir(self.mixamo_ss_latents_path) |
| self.mixamo_ss_latents_list.sort() |
| for ss_latent_name in self.mixamo_ss_latents_list: |
| character_name = ss_latent_name.split('_')[0] |
| cond_img_path = os.path.join(self.mixamo_data_path, 'renders_cond', ss_latent_name[:-4], '000.png') |
| assert os.path.exists(cond_img_path), f'{cond_img_path} not found' |
| self.mixamo_instances[character_name].append([ |
| os.path.join(self.mixamo_ss_latents_path, ss_latent_name), |
| os.path.join(self.mixamo_renders_cond_path, ss_latent_name[:-4], '000.png') |
| ]) |
| print('Ori mixamo data num: ', len(self.mixamo_ss_latents_list)) |
| _mixamo_instances = [] |
| for character_name, instances in self.mixamo_instances.items(): |
| object_num = 0 |
| for _ in range(math.ceil(self.mixamo_data_repeat_ratio)): |
| random.shuffle(instances) |
| i, j = 0, len(instances) - 1 |
| while i < j: |
| _mixamo_instances.append([ |
| instances[i][0], |
| instances[j][0], |
| instances[i][1], |
| instances[j][1] |
| ]) |
| object_num += 1 |
| i += 1 |
| j -= 1 |
| if object_num >= len(instances) * self.mixamo_data_repeat_ratio: |
| break |
| self.mixamo_instances = _mixamo_instances |
| print(f'Repeated Mixamo data num: {len(self.mixamo_instances)}') |
| |
| # ---- load flux editing data |
| self.flux_editing_instances = [] |
| self.flux_editing_3d_list = os.listdir(self.flux_editing_3d_path) |
| self.flux_editing_3d_list.sort() |
| remove_num = 0 |
| for flux_editing_3d_name in self.flux_editing_3d_list: |
| if self.load_data_type == 'ss_latents': |
| ori_ss_latent_path = os.path.join(self.flux_editing_3d_path, flux_editing_3d_name, 'ori_ss_latents.npz') |
| edited_ss_latent_path = os.path.join(self.flux_editing_3d_path, flux_editing_3d_name, 'edit_ss_latents.npz') |
| else: |
| ori_ss_latent_path = os.path.join(self.flux_editing_3d_path, flux_editing_3d_name, 'ori_latents.npz') |
| edited_ss_latent_path = os.path.join(self.flux_editing_3d_path, flux_editing_3d_name, 'edit_latents.npz').replace('Flux_Step_3d_editing_data_v2', 'Flux_Step_3d_editing_data_v3') |
| if not os.path.exists(edited_ss_latent_path): |
| continue |
| if not (os.path.exists(ori_ss_latent_path) and os.path.exists(edited_ss_latent_path)): |
| continue |
| if self.adapt_simple_edit_data: |
| edited_ss_latent_path = edited_ss_latent_path.replace('edit_ss_latents.npz', 'simple_edit_ss_latents.npz') |
| assert os.path.exists(edited_ss_latent_path), f'{edited_ss_latent_path} not found' |
| if self.filter_info is not None and self.flux_editing_confidence_json_path is not None: |
| choose_flag = True |
| for filter_key, filter_range in filter_info.items(): |
| min_val, max_val = filter_range |
| if self.flux_editing_confidence_json[flux_editing_3d_name][filter_key] < min_val or self.flux_editing_confidence_json[flux_editing_3d_name][filter_key] > max_val: |
| choose_flag = False |
| break |
| if not choose_flag: |
| remove_num += 1 |
| continue |
| object_name, index = flux_editing_3d_name.split('_') |
| ori_img_path = os.path.join(self.flux_editing_image_path, object_name, f'ori_{index}.png') |
| # edited_img_path = os.path.join(self.flux_editing_image_path, object_name, f'edited_{index}.png') |
| edit_img_list = os.listdir(os.path.join(self.flux_editing_edited_image_path, flux_editing_3d_name)) |
| edit_img_list.sort() |
| edited_img_path = os.path.join(self.flux_editing_edited_image_path, flux_editing_3d_name, edit_img_list[-1]) |
| assert os.path.exists(ori_img_path), f'{ori_img_path} not found' |
| assert os.path.exists(edited_img_path), f'{edited_img_path} not found' |
| self.flux_editing_instances.append([ |
| ori_ss_latent_path, |
| edited_ss_latent_path, |
| ori_img_path, |
| edited_img_path, |
| ]) |
| print(f'Remove flux editing data (based on confidence) num: {remove_num}') |
| print(f'Flux editing data num: {len(self.flux_editing_instances)}') |
| |
| # ---- load alpaca editing data |
| self.alpaca_editing_instances = [] |
| self.alpaca_editing_3d_list = os.listdir(self.alpaca_editing_3d_path) |
| self.alpaca_editing_3d_list.sort() |
| remove_num = 0 |
| if self.load_data_type == 'ss_latents': |
| for alpaca_editing_3d_name in self.alpaca_editing_3d_list: |
| ori_ss_latent_path = os.path.join(self.alpaca_editing_3d_path, alpaca_editing_3d_name, 'ori_ss_latents.npz') |
| edited_ss_latent_path = os.path.join(self.alpaca_editing_3d_path, alpaca_editing_3d_name, 'edit_ss_latents.npz') |
| if not (os.path.exists(ori_ss_latent_path) and os.path.exists(edited_ss_latent_path)): |
| continue |
| if self.filter_info is not None and self.alpaca_editing_confidence_json_path is not None: |
| choose_flag = True |
| for filter_key, filter_range in filter_info.items(): |
| min_val, max_val = filter_range |
| if self.alpaca_editing_confidence_json[alpaca_editing_3d_name][filter_key] < min_val or self.alpaca_editing_confidence_json[alpaca_editing_3d_name][filter_key] > max_val: |
| choose_flag = False |
| break |
| if not choose_flag: |
| remove_num += 1 |
| continue |
| ori_img_path = os.path.join(self.alpaca_editing_image_path, alpaca_editing_3d_name, 'original.png') |
| if not os.path.exists(ori_img_path): |
| ori_img_path = ori_img_path.replace('open_data', 'open_data2') |
| assert os.path.exists(ori_img_path), f'{ori_img_path} not found' |
| edited_img_path = ori_img_path.replace('original.png', 'after_edited_Step1X-Edit.png') |
| assert os.path.exists(edited_img_path), f'{edited_img_path} not found' |
| self.alpaca_editing_instances.append([ |
| ori_ss_latent_path, |
| edited_ss_latent_path, |
| ori_img_path, |
| edited_img_path, |
| ]) |
| print(f'Remove alpaca editing data (based on confidence) num: {remove_num}') |
| print(f'Alpaca editing data num: {len(self.alpaca_editing_instances)}')''' |
|
|
| print('**********************') |
| print(f'Total editing data num: {len(self.mixamo_instances) + len(self.flux_editing_instances) + len(self.alpaca_editing_instances)}, including:') |
| print(f' - Mixamo: {len(self.mixamo_instances)}') |
| print(f' - Flux editing: {len(self.flux_editing_instances)}') |
| print(f' - Alpaca editing: {len(self.alpaca_editing_instances)}') |
| print('**********************') |
|
|
| |
| '''with open(json_file, 'r') as f: |
| json_info = json.load(f) |
| json_info = json_info[:dataset_num] |
| print('Plan to load {} instances'.format(len(json_info))) |
| |
| self.instances = [] |
| for info in json_info: |
| glb1_path = info['model1_path'] |
| merged_glb_path = info['merged_glb_path'] |
| glb1_sha256 = glb1_path.split('/')[-1].split('.')[0] |
| merged_glb_sha256 = merged_glb_path.split('/')[-1].split('.')[0] |
| exist_glb1 = self.exist_instance(self.roots, glb1_sha256) |
| exist_merged_glb = self.exist_instance(self.roots, merged_glb_sha256) |
| if exist_glb1 and exist_merged_glb: |
| self.instances.append([self.roots, glb1_sha256, merged_glb_sha256]) |
| print('Actually load {} instances'.format(len(self.instances)))''' |
| |
| |
| '''self.metadata = pd.DataFrame() |
| self._stats = {} |
| for root in self.roots: |
| key = os.path.basename(root) |
| self._stats[key] = {} |
| metadata = pd.read_csv(os.path.join(root, 'metadata.csv')) |
| self._stats[key]['Total'] = len(metadata) |
| metadata, stats = self.filter_metadata(metadata) |
| self._stats[key].update(stats) |
| self.instances.extend([(root, sha256) for sha256 in metadata['sha256'].values]) |
| metadata.set_index('sha256', inplace=True) |
| self.metadata = pd.concat([self.metadata, metadata])''' |
| |
|
|
| def _editverse_clean_latent_pair(self, key: str, *, is_alpaca: bool) -> Tuple[str, str]: |
| base = _editverse_clean_encoded_base(self.editverse_clean_root, key, is_alpaca=is_alpaca) |
| if self.load_data_type == 'ss_latents': |
| return str(base / 'ori' / 'ss_latent.npz'), str(base / 'edit' / 'ss_latent.npz') |
| return str(base / 'ori' / 'slat_latent.npz'), str(base / 'edit' / 'slat_latent.npz') |
|
|
| def _editverse_clean_cond_image_pair(self, key: str, value: dict, *, is_alpaca: bool) -> Tuple[str, str]: |
| branch = 'alpaca' if is_alpaca else 'flux' |
| cond_base = Path(self.editverse_clean_root) / 'condition-image' / branch / key |
| ori_candidates = [ |
| cond_base / os.path.basename(value['ori_img_path']), |
| cond_base / 'ori_image.png', |
| ] |
| edit_candidates = [ |
| cond_base / os.path.basename(value['edit_img_path']), |
| cond_base / ('after_edited_Flux.png' if is_alpaca else 'edited_0.png'), |
| ] |
|
|
| ori = next((path for path in ori_candidates if path.is_file()), ori_candidates[0]) |
| edit = next((path for path in edit_candidates if path.is_file()), edit_candidates[0]) |
| return str(ori), str(edit) |
|
|
| def exist_instance(self, root, sha256): |
| cond1 = os.path.exists(os.path.join(root, 'ss_latents', 'ss_enc_conv3d_16l8_fp16', f'{sha256}.npz')) |
| cond2 = os.path.exists(os.path.join(root, 'renders_cond', sha256, 'transforms.json')) |
| return cond1 and cond2 |
| |
| @abstractmethod |
| def filter_metadata(self, metadata: pd.DataFrame) -> Tuple[pd.DataFrame, Dict[str, int]]: |
| pass |
| |
| |
| |
| |
| |
| @abstractmethod |
| def get_instance(self, ori_ss_latent_path: str, edited_ss_latent_path: str, ori_img_path: str, edited_img_path: str) -> Dict[str, Any]: |
| pass |
|
|
| def __len__(self): |
| |
| return len(self.mixamo_instances) + len(self.flux_editing_instances) + len(self.alpaca_editing_instances) |
|
|
| def get_data_path_from_index(self, index) -> Dict[str, Any]: |
| if index < len(self.mixamo_instances): |
| data = self.mixamo_instances[index] |
| elif index < len(self.mixamo_instances) + len(self.flux_editing_instances): |
| data = self.flux_editing_instances[index - len(self.mixamo_instances)] |
| else: |
| data = self.alpaca_editing_instances[index - len(self.mixamo_instances) - len(self.flux_editing_instances)] |
| return data |
|
|
| def __getitem__(self, index) -> Dict[str, Any]: |
| |
| data_path = self.get_data_path_from_index(index) |
| if self.random_ori_edit is not None and np.random.rand() < self.random_ori_edit: |
| another_index = np.random.randint(0, len(self)) |
| another_data_path = self.get_data_path_from_index(another_index) |
| data_path = [another_data_path[0], data_path[1], another_data_path[2], data_path[3]] |
| return self.get_instance(*data_path) |
| |
| |
| |
| |
| def __str__(self): |
| lines = [] |
| lines.append(self.__class__.__name__) |
| |
| lines.append(f' - Total instances: {len(self)}') |
| lines.append(f' - Sources:') |
| lines.append(f' - Mixamo: {len(self.mixamo_instances)}') |
| lines.append(f' - Flux editing: {len(self.flux_editing_instances)}') |
| lines.append(f' - Alpaca editing: {len(self.alpaca_editing_instances)}') |
| return '\n'.join(lines) |
| |
| |
| '''lines.append(f' - Total instances: {len(self)}') |
| lines.append(f' - Sources:') |
| for root, glb1_sha256, merged_glb_sha256 in self.instances: |
| lines.append(f' - {root}:') |
| lines.append(f' - {glb1_sha256}:') |
| lines.append(f' - {merged_glb_sha256}:') |
| return '\n'.join(lines)''' |
| |
| |
| class EditingImageConditionedMixin: |
| def __init__(self, roots, *, image_size=518, **kwargs): |
| self.image_size = image_size |
| super().__init__(roots, **kwargs) |
| |
| self.rembg_session = None |
| |
| def __deepcopy__(self, memo): |
| """ |
| 自定义深度复制逻辑。 |
| """ |
| |
| |
| |
| cls = self.__class__ |
| result = cls.__new__(cls) |
| |
| |
| memo[id(self)] = result |
|
|
| |
| for k, v in self.__dict__.items(): |
| if k == 'rembg_session': |
| |
| |
| continue |
| setattr(result, k, copy.deepcopy(v, memo)) |
|
|
| |
| |
| result.rembg_session = rembg.new_session('u2net') |
| |
| return result |
|
|
| |
| |
| |
| |
| |
| |
| def _get_cond_image(self, image_path, aug_bbox=None): |
| |
| '''image_root = os.path.join(root, 'renders_cond', sha256) |
| with open(os.path.join(image_root, 'transforms.json')) as f: |
| metadata = json.load(f) |
| n_views = len(metadata['frames']) |
| view = np.random.randint(n_views) if view_idx is None else view_idx |
| metadata = metadata['frames'][view] |
| |
| image_path = os.path.join(image_root, metadata['file_path'])''' |
| image = Image.open(image_path) |
| image, aug_bbox, self.rembg_session = preprocess_condition_image( |
| image, self.image_size, self.rembg_session, aug_bbox |
| ) |
| |
| return image, aug_bbox |
|
|
| def get_instance(self, ori_ss_latent_path, edited_ss_latent_path, ori_img_path, edited_img_path): |
| pack = super().get_instance(ori_ss_latent_path, edited_ss_latent_path, ori_img_path, edited_img_path) |
| |
| ori_cond_img, _ = self._get_cond_image(ori_img_path) |
| edited_cond_img, _ = self._get_cond_image(edited_img_path) |
|
|
| pack['ori_cond_img'] = ori_cond_img |
| pack['edited_cond_img'] = edited_cond_img |
|
|
| if self.random_cond_gt and np.random.rand() < 0.5: |
| pack['ori_cond_img'], pack['edited_cond_img'] = pack['edited_cond_img'], pack['ori_cond_img'] |
| pack['ori_ss_latent'], pack['edited_ss_latent'] = pack['edited_ss_latent'], pack['ori_ss_latent'] |
|
|
| pack.setdefault('edit_type', 'editverse') |
|
|
| return pack |
|
|
| |