|
import io |
|
import random |
|
import struct |
|
import tempfile |
|
from contextlib import contextmanager |
|
from typing import List, Union |
|
|
|
import numpy as np |
|
import PIL.Image |
|
import PIL.ImageOps |
|
|
|
from .import_utils import ( |
|
BACKENDS_MAPPING, |
|
is_opencv_available, |
|
) |
|
from .logging import get_logger |
|
|
|
|
|
global_rng = random.Random() |
|
|
|
logger = get_logger(__name__) |
|
|
|
|
|
@contextmanager |
|
def buffered_writer(raw_f): |
|
f = io.BufferedWriter(raw_f) |
|
yield f |
|
f.flush() |
|
|
|
|
|
def export_to_gif(image: List[PIL.Image.Image], output_gif_path: str = None, fps: int = 10) -> str: |
|
if output_gif_path is None: |
|
output_gif_path = tempfile.NamedTemporaryFile(suffix=".gif").name |
|
|
|
image[0].save( |
|
output_gif_path, |
|
save_all=True, |
|
append_images=image[1:], |
|
optimize=False, |
|
duration=1000 // fps, |
|
loop=0, |
|
) |
|
return output_gif_path |
|
|
|
|
|
def export_to_ply(mesh, output_ply_path: str = None): |
|
""" |
|
Write a PLY file for a mesh. |
|
""" |
|
if output_ply_path is None: |
|
output_ply_path = tempfile.NamedTemporaryFile(suffix=".ply").name |
|
|
|
coords = mesh.verts.detach().cpu().numpy() |
|
faces = mesh.faces.cpu().numpy() |
|
rgb = np.stack([mesh.vertex_channels[x].detach().cpu().numpy() for x in "RGB"], axis=1) |
|
|
|
with buffered_writer(open(output_ply_path, "wb")) as f: |
|
f.write(b"ply\n") |
|
f.write(b"format binary_little_endian 1.0\n") |
|
f.write(bytes(f"element vertex {len(coords)}\n", "ascii")) |
|
f.write(b"property float x\n") |
|
f.write(b"property float y\n") |
|
f.write(b"property float z\n") |
|
if rgb is not None: |
|
f.write(b"property uchar red\n") |
|
f.write(b"property uchar green\n") |
|
f.write(b"property uchar blue\n") |
|
if faces is not None: |
|
f.write(bytes(f"element face {len(faces)}\n", "ascii")) |
|
f.write(b"property list uchar int vertex_index\n") |
|
f.write(b"end_header\n") |
|
|
|
if rgb is not None: |
|
rgb = (rgb * 255.499).round().astype(int) |
|
vertices = [ |
|
(*coord, *rgb) |
|
for coord, rgb in zip( |
|
coords.tolist(), |
|
rgb.tolist(), |
|
) |
|
] |
|
format = struct.Struct("<3f3B") |
|
for item in vertices: |
|
f.write(format.pack(*item)) |
|
else: |
|
format = struct.Struct("<3f") |
|
for vertex in coords.tolist(): |
|
f.write(format.pack(*vertex)) |
|
|
|
if faces is not None: |
|
format = struct.Struct("<B3I") |
|
for tri in faces.tolist(): |
|
f.write(format.pack(len(tri), *tri)) |
|
|
|
return output_ply_path |
|
|
|
|
|
def export_to_obj(mesh, output_obj_path: str = None): |
|
if output_obj_path is None: |
|
output_obj_path = tempfile.NamedTemporaryFile(suffix=".obj").name |
|
|
|
verts = mesh.verts.detach().cpu().numpy() |
|
faces = mesh.faces.cpu().numpy() |
|
|
|
vertex_colors = np.stack([mesh.vertex_channels[x].detach().cpu().numpy() for x in "RGB"], axis=1) |
|
vertices = [ |
|
"{} {} {} {} {} {}".format(*coord, *color) for coord, color in zip(verts.tolist(), vertex_colors.tolist()) |
|
] |
|
|
|
faces = ["f {} {} {}".format(str(tri[0] + 1), str(tri[1] + 1), str(tri[2] + 1)) for tri in faces.tolist()] |
|
|
|
combined_data = ["v " + vertex for vertex in vertices] + faces |
|
|
|
with open(output_obj_path, "w") as f: |
|
f.writelines("\n".join(combined_data)) |
|
|
|
|
|
def export_to_video( |
|
video_frames: Union[List[np.ndarray], List[PIL.Image.Image]], output_video_path: str = None, fps: int = 10 |
|
) -> str: |
|
if is_opencv_available(): |
|
import cv2 |
|
else: |
|
raise ImportError(BACKENDS_MAPPING["opencv"][1].format("export_to_video")) |
|
if output_video_path is None: |
|
output_video_path = tempfile.NamedTemporaryFile(suffix=".mp4").name |
|
|
|
if isinstance(video_frames[0], np.ndarray): |
|
video_frames = [(frame * 255).astype(np.uint8) for frame in video_frames] |
|
|
|
elif isinstance(video_frames[0], PIL.Image.Image): |
|
video_frames = [np.array(frame) for frame in video_frames] |
|
|
|
fourcc = cv2.VideoWriter_fourcc(*"mp4v") |
|
h, w, c = video_frames[0].shape |
|
video_writer = cv2.VideoWriter(output_video_path, fourcc, fps=fps, frameSize=(w, h)) |
|
for i in range(len(video_frames)): |
|
img = cv2.cvtColor(video_frames[i], cv2.COLOR_RGB2BGR) |
|
video_writer.write(img) |
|
return output_video_path |
|
|