Spaces:
Sleeping
Sleeping
| import os | |
| import cv2 | |
| import numpy as np | |
| import tempfile | |
| from tqdm import tqdm | |
| from subprocess import call | |
| import trimesh | |
| from scipy.io import wavfile | |
| import librosa | |
| class Struct(object): | |
| def __init__(self, **kwargs): | |
| for key, val in kwargs.items(): | |
| setattr(self, key, val) | |
| def add_image_text(img, text, color=(0,0,255), w=800, h=800): | |
| font = cv2.FONT_HERSHEY_SIMPLEX | |
| img = np.require(img, dtype='f4', requirements=['O', 'W']) | |
| img.flags.writeable = True | |
| img1 = img.copy() | |
| img1 = cv2.putText(img1, '%s' % (text), (50, 100), font, 2, color, 2, 1) | |
| img1 = cv2.rectangle(img1, (0, 0), (w, h), color, thickness=3) | |
| return img1 | |
| class RenderTool: | |
| def __init__(self, out_path): | |
| path = os.path.join(os.getcwd(), 'visualise/smplx/SMPLX_NEUTRAL.npz') | |
| model_data = np.load(path, allow_pickle=True) | |
| data_struct = Struct(**model_data) | |
| self.f = data_struct.f # faces | |
| self.out_path = out_path | |
| if not os.path.exists(self.out_path): | |
| os.makedirs(self.out_path) | |
| def _render_sequences(self, cur_wav_file, v_list, j=-1, run_in_parallel=False): | |
| symbol = '/' | |
| print("Render {} {} sequence.".format(cur_wav_file.split(symbol)[-2], cur_wav_file.split(symbol)[-1])) | |
| directory = os.path.join(self.out_path, cur_wav_file.split(symbol)[2].split(symbol)[0]) | |
| if not os.path.exists(directory): | |
| os.makedirs(directory) | |
| if j == -1: | |
| video_fname = os.path.join(directory, '%s.mp4' % cur_wav_file.split(symbol)[-1].split('.')[-2].split(symbol)[-1]) | |
| elif j == -2: | |
| video_fname = os.path.join(directory, cur_wav_file.split(symbol)[-3]+'--%s.mp4' % cur_wav_file.split(symbol)[-1].split('.')[-2].split(symbol)[-1]) | |
| else: | |
| video_fname = os.path.join(directory, str(j)+'_%s.mp4' % cur_wav_file.split(symbol)[-1].split('.')[-2].split(symbol)[-1]) | |
| self._render_sequences_helper(video_fname, cur_wav_file, v_list) | |
| def _render_sequences_helper(self, video_fname, cur_wav_file, v_list): | |
| num_frames = v_list[0].shape[0] | |
| # Prepare output frames folder | |
| frames_dir = os.path.join(os.path.dirname(video_fname), "frames_tmp") | |
| os.makedirs(frames_dir, exist_ok=True) | |
| center = np.mean(v_list[0][0], axis=0) | |
| for i_frame in tqdm(range(num_frames)): | |
| cur_img_list = [] | |
| for i in range(len(v_list)): | |
| mesh = trimesh.Trimesh(vertices=v_list[i][i_frame], faces=self.f) | |
| scene = trimesh.Scene(mesh) | |
| png = scene.save_image(resolution=[800, 800], visible=True) | |
| img_array = np.asarray(bytearray(png), dtype=np.uint8) | |
| img = cv2.imdecode(img_array, cv2.IMREAD_COLOR) | |
| cur_img_list.append(img) | |
| if len(cur_img_list) == 1: | |
| final_img = cur_img_list[0] | |
| else: | |
| final_img = np.hstack(cur_img_list) | |
| frame_path = os.path.join(frames_dir, f"frame_{i_frame:04d}.png") | |
| cv2.imwrite(frame_path, final_img) | |
| # Create video from frames | |
| tmp_audio_file = tempfile.NamedTemporaryFile('w', suffix='.wav', dir=os.path.dirname(video_fname)) | |
| tmp_audio_file.close() | |
| audio, sr = librosa.load(cur_wav_file, sr=16000) | |
| wavfile.write(tmp_audio_file.name, sr, audio) | |
| tmp_video_file = tempfile.NamedTemporaryFile('w', suffix='.mp4', dir=os.path.dirname(video_fname)) | |
| tmp_video_file.close() | |
| cmd_frames_to_video = ( | |
| f"ffmpeg -framerate 30 -i {frames_dir}/frame_%04d.png -c:v libx264 -pix_fmt yuv420p {tmp_video_file.name}" | |
| ).split() | |
| call(cmd_frames_to_video) | |
| cmd_merge_audio = ( | |
| f"ffmpeg -i {tmp_video_file.name} -i {tmp_audio_file.name} -vcodec copy -acodec aac {video_fname}" | |
| ).split() | |
| call(cmd_merge_audio) | |
| # Cleanup | |
| os.remove(tmp_audio_file.name) | |
| os.remove(tmp_video_file.name) | |
| for f in os.listdir(frames_dir): | |
| os.remove(os.path.join(frames_dir, f)) | |
| os.rmdir(frames_dir) | |