From 39353a36375a29e7127ada0546cdb7fe1c709511 Mon Sep 17 00:00:00 2001 From: Denis Kochetov Date: Wed, 30 Jul 2025 10:25:17 +0000 Subject: [PATCH] remove pyrender code --- .../partcrafter_src/utils/render_utils.py | 778 +++++++++--------- 1 file changed, 390 insertions(+), 388 deletions(-) diff --git a/Gen_3D_Modules/PartCrafter/partcrafter_src/utils/render_utils.py b/Gen_3D_Modules/PartCrafter/partcrafter_src/utils/render_utils.py index ed0695d..b2b137f 100644 --- a/Gen_3D_Modules/PartCrafter/partcrafter_src/utils/render_utils.py +++ b/Gen_3D_Modules/PartCrafter/partcrafter_src/utils/render_utils.py @@ -5,14 +5,14 @@ import numpy as np from PIL import Image import trimesh from trimesh.transformations import rotation_matrix -import pyrender +# import pyrender # Commented out - not needed for core functionality from diffusers.utils import export_to_video from diffusers.utils.loading_utils import load_video import torch from torchvision.utils import make_grid import math -os.environ['PYOPENGL_PLATFORM'] = 'egl' +# os.environ['PYOPENGL_PLATFORM'] = 'egl' # Commented out - not needed without pyrender def explode_mesh(mesh, explosion_scale=0.4): # ensure we have a Scene @@ -63,409 +63,411 @@ def explode_mesh(mesh, explosion_scale=0.4): return exploded +# All render functions below use pyrender and are commented out +# They are not needed for core PartCrafter functionality + +# def render( +# scene: pyrender.Scene, +# renderer: pyrender.Renderer, +# camera: pyrender.Camera, +# pose: np.ndarray, +# light: Optional[pyrender.Light] = None, +# normalize_depth: bool = False, +# flags: int = pyrender.constants.RenderFlags.NONE, +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[Tuple[np.ndarray, np.ndarray], Tuple[Image.Image, Image.Image]]: +# camera_node = scene.add(camera, pose=pose) +# if light is not None: +# light_node = scene.add(light, pose=pose) +# image, depth = renderer.render( +# scene, +# flags=flags +# ) +# scene.remove_node(camera_node) +# if light is not None: +# scene.remove_node(light_node) +# if normalize_depth or return_type == 'pil': +# depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0 +# if return_type == 'pil': +# image = Image.fromarray(image) +# depth = Image.fromarray(depth.astype(np.uint8)) +# return image, depth + +# def rotation_matrix_from_vectors(vec1, vec2): +# a, b = vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2) +# v = np.cross(a, b) +# c = np.dot(a, b) +# s = np.linalg.norm(v) +# if s == 0: +# return np.eye(3) if c > 0 else -np.eye(3) +# kmat = np.array([ +# [0, -v[2], v[1]], +# [v[2], 0, -v[0]], +# [-v[1], v[0], 0] +# ]) +# return np.eye(3) + kmat + kmat @ kmat * ((1 - c) / (s ** 2)) + +# def create_circular_camera_positions( +# num_views: int, +# radius: float, +# axis: np.ndarray = np.array([0.0, 1.0, 0.0]) +# ) -> List[np.ndarray]: +# # Create a list of positions for a circular camera trajectory +# # around the given axis with the given radius. +# positions = [] +# axis = axis / np.linalg.norm(axis) +# for i in range(num_views): +# theta = 2 * np.pi * i / num_views +# position = np.array([ +# np.sin(theta) * radius, +# 0.0, +# np.cos(theta) * radius +# ]) +# if not np.allclose(axis, np.array([0.0, 1.0, 0.0])): +# R = rotation_matrix_from_vectors(np.array([0.0, 1.0, 0.0]), axis) +# position = R @ position +# positions.append(position) +# return positions + +# def create_circular_camera_poses( +# num_views: int, +# radius: float, +# axis: np.ndarray = np.array([0.0, 1.0, 0.0]) +# ) -> List[np.ndarray]: +# # Create a list of poses for a circular camera trajectory +# # around the given axis with the given radius. +# # The camera always looks at the origin. +# # The up vector is always [0, 1, 0]. +# canonical_pose = np.array([ +# [1.0, 0.0, 0.0, 0.0], +# [0.0, 1.0, 0.0, 0.0], +# [0.0, 0.0, 1.0, radius], +# [0.0, 0.0, 0.0, 1.0] +# ]) +# poses = [] +# for i in range(num_views): +# theta = 2 * np.pi * i / num_views +# R = rotation_matrix( +# angle=theta, +# direction=axis, +# point=[0, 0, 0] +# ) +# pose = R @ canonical_pose +# poses.append(pose) +# return poses + +# def render_views_around_mesh( +# mesh: Union[trimesh.Trimesh, trimesh.Scene], +# num_views: int = 36, +# radius: float = 3.5, +# axis: np.ndarray = np.array([0.0, 1.0, 0.0]), +# image_size: tuple = (512, 512), +# fov: float = 40.0, +# light_intensity: Optional[float] = 5.0, +# znear: float = 0.1, +# zfar: float = 10.0, +# normalize_depth: bool = False, +# flags: int = pyrender.constants.RenderFlags.NONE, +# return_depth: bool = False, +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[ +# List[Image.Image], +# List[np.ndarray], +# Tuple[List[Image.Image], List[Image.Image]], +# Tuple[List[np.ndarray], List[np.ndarray]] +# ]: + +# meshes = [] +# scenes = [] -def render( - scene: pyrender.Scene, - renderer: pyrender.Renderer, - camera: pyrender.Camera, - pose: np.ndarray, - light: Optional[pyrender.Light] = None, - normalize_depth: bool = False, - flags: int = pyrender.constants.RenderFlags.NONE, - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[Tuple[np.ndarray, np.ndarray], Tuple[Image.Image, Image.Image]]: - camera_node = scene.add(camera, pose=pose) - if light is not None: - light_node = scene.add(light, pose=pose) - image, depth = renderer.render( - scene, - flags=flags - ) - scene.remove_node(camera_node) - if light is not None: - scene.remove_node(light_node) - if normalize_depth or return_type == 'pil': - depth = (depth - depth.min()) / (depth.max() - depth.min()) * 255.0 - if return_type == 'pil': - image = Image.fromarray(image) - depth = Image.fromarray(depth.astype(np.uint8)) - return image, depth - -def rotation_matrix_from_vectors(vec1, vec2): - a, b = vec1 / np.linalg.norm(vec1), vec2 / np.linalg.norm(vec2) - v = np.cross(a, b) - c = np.dot(a, b) - s = np.linalg.norm(v) - if s == 0: - return np.eye(3) if c > 0 else -np.eye(3) - kmat = np.array([ - [0, -v[2], v[1]], - [v[2], 0, -v[0]], - [-v[1], v[0], 0] - ]) - return np.eye(3) + kmat + kmat @ kmat * ((1 - c) / (s ** 2)) - -def create_circular_camera_positions( - num_views: int, - radius: float, - axis: np.ndarray = np.array([0.0, 1.0, 0.0]) -) -> List[np.ndarray]: - # Create a list of positions for a circular camera trajectory - # around the given axis with the given radius. - positions = [] - axis = axis / np.linalg.norm(axis) - for i in range(num_views): - theta = 2 * np.pi * i / num_views - position = np.array([ - np.sin(theta) * radius, - 0.0, - np.cos(theta) * radius - ]) - if not np.allclose(axis, np.array([0.0, 1.0, 0.0])): - R = rotation_matrix_from_vectors(np.array([0.0, 1.0, 0.0]), axis) - position = R @ position - positions.append(position) - return positions - -def create_circular_camera_poses( - num_views: int, - radius: float, - axis: np.ndarray = np.array([0.0, 1.0, 0.0]) -) -> List[np.ndarray]: - # Create a list of poses for a circular camera trajectory - # around the given axis with the given radius. - # The camera always looks at the origin. - # The up vector is always [0, 1, 0]. - canonical_pose = np.array([ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, radius], - [0.0, 0.0, 0.0, 1.0] - ]) - poses = [] - for i in range(num_views): - theta = 2 * np.pi * i / num_views - R = rotation_matrix( - angle=theta, - direction=axis, - point=[0, 0, 0] - ) - pose = R @ canonical_pose - poses.append(pose) - return poses - -def render_views_around_mesh( - mesh: Union[trimesh.Trimesh, trimesh.Scene], - num_views: int = 36, - radius: float = 3.5, - axis: np.ndarray = np.array([0.0, 1.0, 0.0]), - image_size: tuple = (512, 512), - fov: float = 40.0, - light_intensity: Optional[float] = 5.0, - znear: float = 0.1, - zfar: float = 10.0, - normalize_depth: bool = False, - flags: int = pyrender.constants.RenderFlags.NONE, - return_depth: bool = False, - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[ - List[Image.Image], - List[np.ndarray], - Tuple[List[Image.Image], List[Image.Image]], - Tuple[List[np.ndarray], List[np.ndarray]] - ]: - - meshes = [] - scenes = [] - - if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): - raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") - if isinstance(mesh, trimesh.Trimesh): - for i in range(num_views): - scenes.append(pyrender.Scene.from_trimesh_scene(trimesh.Scene(mesh))) - else: - for i in range(num_views): - value = math.sin(math.pi * (i - 1) / num_views) - scenes.append(pyrender.Scene.from_trimesh_scene(explode_mesh(mesh, 0.2 * value), - ambient_light=[0.02, 0.02, 0.02], - bg_color=[0.0, 0.0, 0.0, 1.0])) +# if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): +# raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") +# if isinstance(mesh, trimesh.Trimesh): +# for i in range(num_views): +# scenes.append(pyrender.Scene.from_trimesh_scene(trimesh.Scene(mesh))) +# else: +# for i in range(num_views): +# value = math.sin(math.pi * (i - 1) / num_views) +# scenes.append(pyrender.Scene.from_trimesh_scene(explode_mesh(mesh, 0.2 * value), +# ambient_light=[0.02, 0.02, 0.02], +# bg_color=[0.0, 0.0, 0.0, 1.0])) - light = pyrender.DirectionalLight( - color=np.ones(3), - intensity=light_intensity - ) if light_intensity is not None else None - camera = pyrender.PerspectiveCamera( - yfov=np.deg2rad(fov), - aspectRatio=image_size[0]/image_size[1], - znear=znear, - zfar=zfar - ) - renderer = pyrender.OffscreenRenderer(*image_size) +# light = pyrender.DirectionalLight( +# color=np.ones(3), +# intensity=light_intensity +# ) if light_intensity is not None else None +# camera = pyrender.PerspectiveCamera( +# yfov=np.deg2rad(fov), +# aspectRatio=image_size[0]/image_size[1], +# znear=znear, +# zfar=zfar +# ) +# renderer = pyrender.OffscreenRenderer(*image_size) - camera_poses = create_circular_camera_poses( - num_views, - radius, - axis = axis - ) +# camera_poses = create_circular_camera_poses( +# num_views, +# radius, +# axis = axis +# ) - images, depths = [], [] - for i, pose in enumerate(camera_poses): - image, depth = render( - scenes[i], renderer, camera, pose, light, - normalize_depth=normalize_depth, - flags=flags, - return_type=return_type - ) - images.append(image) - depths.append(depth) +# images, depths = [], [] +# for i, pose in enumerate(camera_poses): +# image, depth = render( +# scenes[i], renderer, camera, pose, light, +# normalize_depth=normalize_depth, +# flags=flags, +# return_type=return_type +# ) +# images.append(image) +# depths.append(depth) - renderer.delete() +# renderer.delete() - if return_depth: - return images, depths - return images +# if return_depth: +# return images, depths +# return images -def render_normal_views_around_mesh( - mesh: Union[trimesh.Trimesh, trimesh.Scene], - num_views: int = 36, - radius: float = 3.5, - axis: np.ndarray = np.array([0.0, 1.0, 0.0]), - image_size: tuple = (512, 512), - fov: float = 40.0, - light_intensity: Optional[float] = 5.0, - znear: float = 0.1, - zfar: float = 10.0, - normalize_depth: bool = False, - flags: int = pyrender.constants.RenderFlags.NONE, - return_depth: bool = False, - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[ - List[Image.Image], - List[np.ndarray], - Tuple[List[Image.Image], List[Image.Image]], - Tuple[List[np.ndarray], List[np.ndarray]] - ]: +# def render_normal_views_around_mesh( +# mesh: Union[trimesh.Trimesh, trimesh.Scene], +# num_views: int = 36, +# radius: float = 3.5, +# axis: np.ndarray = np.array([0.0, 1.0, 0.0]), +# image_size: tuple = (512, 512), +# fov: float = 40.0, +# light_intensity: Optional[float] = 5.0, +# znear: float = 0.1, +# zfar: float = 10.0, +# normalize_depth: bool = False, +# flags: int = pyrender.constants.RenderFlags.NONE, +# return_depth: bool = False, +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[ +# List[Image.Image], +# List[np.ndarray], +# Tuple[List[Image.Image], List[Image.Image]], +# Tuple[List[np.ndarray], List[np.ndarray]] +# ]: - if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): - raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") - if isinstance(mesh, trimesh.Scene): - mesh = mesh.to_geometry() - normals = mesh.vertex_normals - colors = ((normals + 1.0) / 2.0 * 255).astype(np.uint8) - mesh.visual = trimesh.visual.ColorVisuals( - mesh=mesh, - vertex_colors=colors - ) - mesh = trimesh.Scene(mesh) - return render_views_around_mesh( - mesh, num_views, radius, axis, - image_size, fov, light_intensity, znear, zfar, - normalize_depth, flags, - return_depth, return_type - ) +# if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): +# raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") +# if isinstance(mesh, trimesh.Scene): +# mesh = mesh.to_geometry() +# normals = mesh.vertex_normals +# colors = ((normals + 1.0) / 2.0 * 255).astype(np.uint8) +# mesh.visual = trimesh.visual.ColorVisuals( +# mesh=mesh, +# vertex_colors=colors +# ) +# mesh = trimesh.Scene(mesh) +# return render_views_around_mesh( +# mesh, num_views, radius, axis, +# image_size, fov, light_intensity, znear, zfar, +# normalize_depth, flags, +# return_depth, return_type +# ) -def create_camera_pose_on_sphere( - azimuth: float = 0.0, # in degrees - elevation: float = 0.0, # in degrees - radius: float = 3.5, -) -> np.ndarray: - # Create a camera pose for a given azimuth and elevation - # with the given radius. - # The camera always looks at the origin. - # The up vector is always [0, 1, 0]. - canonical_pose = np.array([ - [1.0, 0.0, 0.0, 0.0], - [0.0, 1.0, 0.0, 0.0], - [0.0, 0.0, 1.0, radius], - [0.0, 0.0, 0.0, 1.0] - ]) - azimuth = np.deg2rad(azimuth) - elevation = np.deg2rad(elevation) - position = np.array([ - np.cos(elevation) * np.sin(azimuth), - np.sin(elevation), - np.cos(elevation) * np.cos(azimuth), - ]) - R = np.eye(4) - R[:3, :3] = rotation_matrix_from_vectors( - np.array([0.0, 0.0, 1.0]), - position - ) - pose = R @ canonical_pose - return pose +# def create_camera_pose_on_sphere( +# azimuth: float = 0.0, # in degrees +# elevation: float = 0.0, # in degrees +# radius: float = 3.5, +# ) -> np.ndarray: +# # Create a camera pose for a given azimuth and elevation +# # with the given radius. +# # The camera always looks at the origin. +# # The up vector is always [0, 1, 0]. +# canonical_pose = np.array([ +# [1.0, 0.0, 0.0, 0.0], +# [0.0, 1.0, 0.0, 0.0], +# [0.0, 0.0, 1.0, radius], +# [0.0, 0.0, 0.0, 1.0] +# ]) +# azimuth = np.deg2rad(azimuth) +# elevation = np.deg2rad(elevation) +# position = np.array([ +# np.cos(elevation) * np.sin(azimuth), +# np.sin(elevation), +# np.cos(elevation) * np.cos(azimuth), +# ]) +# R = np.eye(4) +# R[:3, :3] = rotation_matrix_from_vectors( +# np.array([0.0, 0.0, 1.0]), +# position +# ) +# pose = R @ canonical_pose +# return pose -def render_single_view( - mesh: Union[trimesh.Trimesh, trimesh.Scene], - azimuth: float = 0.0, # in degrees - elevation: float = 0.0, # in degrees - radius: float = 3.5, - image_size: tuple = (512, 512), - fov: float = 40.0, - light_intensity: Optional[float] = 5.0, - num_env_lights: int = 0, - znear: float = 0.1, - zfar: float = 10.0, - normalize_depth: bool = False, - flags: int = pyrender.constants.RenderFlags.NONE, - return_depth: bool = False, - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[ - Image.Image, - np.ndarray, - Tuple[Image.Image, Image.Image], - Tuple[np.ndarray, np.ndarray] - ]: +# def render_single_view( +# mesh: Union[trimesh.Trimesh, trimesh.Scene], +# azimuth: float = 0.0, # in degrees +# elevation: float = 0.0, # in degrees +# radius: float = 3.5, +# image_size: tuple = (512, 512), +# fov: float = 40.0, +# light_intensity: Optional[float] = 5.0, +# num_env_lights: int = 0, +# znear: float = 0.1, +# zfar: float = 10.0, +# normalize_depth: bool = False, +# flags: int = pyrender.constants.RenderFlags.NONE, +# return_depth: bool = False, +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[ +# Image.Image, +# np.ndarray, +# Tuple[Image.Image, Image.Image], +# Tuple[np.ndarray, np.ndarray] +# ]: - if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): - raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") - if isinstance(mesh, trimesh.Trimesh): - mesh = trimesh.Scene(mesh) +# if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): +# raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") +# if isinstance(mesh, trimesh.Trimesh): +# mesh = trimesh.Scene(mesh) - scene = pyrender.Scene.from_trimesh_scene(mesh) - light = pyrender.DirectionalLight( - color=np.ones(3), - intensity=light_intensity - ) if light_intensity is not None else None - camera = pyrender.PerspectiveCamera( - yfov=np.deg2rad(fov), - aspectRatio=image_size[0]/image_size[1], - znear=znear, - zfar=zfar - ) - renderer = pyrender.OffscreenRenderer(*image_size) +# scene = pyrender.Scene.from_trimesh_scene(mesh) +# light = pyrender.DirectionalLight( +# color=np.ones(3), +# intensity=light_intensity +# ) if light_intensity is not None else None +# camera = pyrender.PerspectiveCamera( +# yfov=np.deg2rad(fov), +# aspectRatio=image_size[0]/image_size[1], +# znear=znear, +# zfar=zfar +# ) +# renderer = pyrender.OffscreenRenderer(*image_size) - camera_pose = create_camera_pose_on_sphere( - azimuth, - elevation, - radius - ) +# camera_pose = create_camera_pose_on_sphere( +# azimuth, +# elevation, +# radius +# ) - if num_env_lights > 0: - env_light_poses = create_circular_camera_poses( - num_env_lights, - radius, - axis = np.array([0.0, 1.0, 0.0]) - ) - for pose in env_light_poses: - scene.add(pyrender.DirectionalLight( - color=np.ones(3), - intensity=light_intensity - ), pose=pose) - # set light to None - light = None +# if num_env_lights > 0: +# env_light_poses = create_circular_camera_poses( +# num_env_lights, +# radius, +# axis = np.array([0.0, 1.0, 0.0]) +# ) +# for pose in env_light_poses: +# scene.add(pyrender.DirectionalLight( +# color=np.ones(3), +# intensity=light_intensity +# ), pose=pose) +# # set light to None +# light = None - image, depth = render( - scene, renderer, camera, camera_pose, light, - normalize_depth=normalize_depth, - flags=flags, - return_type=return_type - ) - renderer.delete() +# image, depth = render( +# scene, renderer, camera, camera_pose, light, +# normalize_depth=normalize_depth, +# flags=flags, +# return_type=return_type +# ) +# renderer.delete() - if return_depth: - return image, depth - return image +# if return_depth: +# return image, depth +# return image -def render_normal_single_view( - mesh: Union[trimesh.Trimesh, trimesh.Scene], - azimuth: float = 0.0, # in degrees - elevation: float = 0.0, # in degrees - radius: float = 3.5, - image_size: tuple = (512, 512), - fov: float = 40.0, - light_intensity: Optional[float] = 5.0, - znear: float = 0.1, - zfar: float = 10.0, - normalize_depth: bool = False, - flags: int = pyrender.constants.RenderFlags.NONE, - return_depth: bool = False, - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[ - Image.Image, - np.ndarray, - Tuple[Image.Image, Image.Image], - Tuple[np.ndarray, np.ndarray] - ]: +# def render_normal_single_view( +# mesh: Union[trimesh.Trimesh, trimesh.Scene], +# azimuth: float = 0.0, # in degrees +# elevation: float = 0.0, # in degrees +# radius: float = 3.5, +# image_size: tuple = (512, 512), +# fov: float = 40.0, +# light_intensity: Optional[float] = 5.0, +# znear: float = 0.1, +# zfar: float = 10.0, +# normalize_depth: bool = False, +# flags: int = pyrender.constants.RenderFlags.NONE, +# return_depth: bool = False, +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[ +# Image.Image, +# np.ndarray, +# Tuple[Image.Image, Image.Image], +# Tuple[np.ndarray, np.ndarray] +# ]: - if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): - raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") - if isinstance(mesh, trimesh.Scene): - mesh = mesh.to_geometry() - normals = mesh.vertex_normals - colors = ((normals + 1.0) / 2.0 * 255).astype(np.uint8) - mesh.visual = trimesh.visual.ColorVisuals( - mesh=mesh, - vertex_colors=colors - ) - mesh = trimesh.Scene(mesh) - return render_single_view( - mesh, azimuth, elevation, radius, - image_size, fov, light_intensity, znear, zfar, - normalize_depth, flags, - return_depth, return_type - ) +# if not isinstance(mesh, (trimesh.Trimesh, trimesh.Scene)): +# raise ValueError("mesh must be a trimesh.Trimesh or trimesh.Scene object") +# if isinstance(mesh, trimesh.Scene): +# mesh = mesh.to_geometry() +# normals = mesh.vertex_normals +# colors = ((normals + 1.0) / 2.0 * 255).astype(np.uint8) +# mesh.visual = trimesh.visual.ColorVisuals( +# mesh=mesh, +# vertex_colors=colors +# ) +# mesh = trimesh.Scene(mesh) +# return render_single_view( +# mesh, azimuth, elevation, radius, +# image_size, fov, light_intensity, znear, zfar, +# normalize_depth, flags, +# return_depth, return_type +# ) -def export_renderings( - images: List[Image.Image], - export_path: str, - fps: int = 36, - loop: int = 0 -): - export_type = export_path.split('.')[-1] - if export_type == 'mp4': - export_to_video( - images, - export_path, - fps=fps, - ) - elif export_type == 'gif': - duration = 1000 / fps - images[0].save( - export_path, - save_all=True, - append_images=images[1:], - duration=duration, - loop=loop - ) - else: - raise ValueError(f'Unknown export type: {export_type}') +# def export_renderings( +# images: List[Image.Image], +# export_path: str, +# fps: int = 36, +# loop: int = 0 +# ): +# export_type = export_path.split('.')[-1] +# if export_type == 'mp4': +# export_to_video( +# images, +# export_path, +# fps=fps, +# ) +# elif export_type == 'gif': +# duration = 1000 / fps +# images[0].save( +# export_path, +# save_all=True, +# append_images=images[1:], +# duration=duration, +# loop=loop +# ) +# else: +# raise ValueError(f'Unknown export type: {export_type}') -def make_grid_for_images_or_videos( - images_or_videos: Union[List[Image.Image], List[List[Image.Image]]], - nrow: int = 4, - padding: int = 0, - pad_value: int = 0, - image_size: tuple = (512, 512), - return_type: Literal['pil', 'ndarray'] = 'pil' -) -> Union[Image.Image, List[Image.Image], np.ndarray]: - if isinstance(images_or_videos[0], Image.Image): - images = [np.array(image.resize(image_size).convert('RGB')) for image in images_or_videos] - images = np.stack(images, axis=0).transpose(0, 3, 1, 2) # [N, C, H, W] - images = torch.from_numpy(images) - image_grid = make_grid( - images, - nrow=nrow, - padding=padding, - pad_value=pad_value, - normalize=False - ) # [C, H', W'] - image_grid = image_grid.cpu().numpy() - if return_type == 'pil': - image_grid = Image.fromarray(image_grid.transpose(1, 2, 0)) - return image_grid - elif isinstance(images_or_videos[0], list) and isinstance(images_or_videos[0][0], Image.Image): - image_grids = [] - for i in range(len(images_or_videos[0])): - images = [video[i] for video in images_or_videos] - image_grid = make_grid_for_images_or_videos( - images, - nrow=nrow, - padding=padding, - return_type=return_type - ) - image_grids.append(image_grid) - if return_type == 'ndarray': - image_grids = np.stack(image_grids, axis=0) - return image_grids - else: - raise ValueError(f'Unknown input type: {type(images_or_videos[0])}') \ No newline at end of file +# def make_grid_for_images_or_videos( +# images_or_videos: Union[List[Image.Image], List[List[Image.Image]]], +# nrow: int = 4, +# padding: int = 0, +# pad_value: int = 0, +# image_size: tuple = (512, 512), +# return_type: Literal['pil', 'ndarray'] = 'pil' +# ) -> Union[Image.Image, List[Image.Image], np.ndarray]: +# if isinstance(images_or_videos[0], Image.Image): +# images = [np.array(image.resize(image_size).convert('RGB')) for image in images_or_videos] +# images = np.stack(images, axis=0).transpose(0, 3, 1, 2) # [N, C, H, W] +# images = torch.from_numpy(images) +# image_grid = make_grid( +# images, +# nrow=nrow, +# padding=padding, +# pad_value=pad_value, +# normalize=False +# ) # [C, H', W'] +# image_grid = image_grid.cpu().numpy() +# if return_type == 'pil': +# image_grid = Image.fromarray(image_grid.transpose(1, 2, 0)) +# return image_grid +# elif isinstance(images_or_videos[0], list) and isinstance(images_or_videos[0][0], Image.Image): +# image_grids = [] +# for i in range(len(images_or_videos[0])): +# images = [video[i] for video in images_or_videos] +# image_grid = make_grid_for_images_or_videos( +# images, +# nrow=nrow, +# padding=padding, +# return_type=return_type +# ) +# image_grids.append(image_grid) +# if return_type == 'ndarray': +# image_grids = np.stack(image_grids, axis=0) +# return image_grids +# else: +# raise ValueError(f'Unknown input type: {type(images_or_videos[0])}') \ No newline at end of file