import sys from src.utils.img_utils import pil_to_cv2, cv2_to_pil, center_crop_cv2, pils_from_video, save_videos_from_pils, save_video_from_cv2_list from PIL import Image import cv2 from IPython import embed import numpy as np import copy from src.utils.motion_utils import motion_sync import pathlib import torch import pickle from glob import glob import os from src.models.dwpose.dwpose_detector import dwpose_detector as dwprocessor from src.models.dwpose.util import draw_pose import decord from tqdm import tqdm from moviepy.editor import AudioFileClip, VideoFileClip from multiprocessing.pool import ThreadPool ################################## base_dir = "root" tasks = ["emtd"] process_num = 800 #1266 start = 0 end = process_num + start ################################# MAX_SIZE = 768 def convert_fps(src_path, tgt_path, tgt_fps=24, tgt_sr=16000): clip = VideoFileClip(src_path) new_clip = clip.set_fps(tgt_fps) if tgt_fps is not None: audio = new_clip.audio audio = audio.set_fps(tgt_sr) new_clip = new_clip.set_audio(audio) new_clip.write_videofile(tgt_path, codec='libx264', audio_codec='aac') def get_video_pose( video_path: str, sample_stride: int=1, max_frame=None): # read input video vr = decord.VideoReader(video_path, ctx=decord.cpu(0)) sample_stride *= max(1, int(vr.get_avg_fps() / 24)) frames = vr.get_batch(list(range(0, len(vr), sample_stride))).asnumpy() if max_frame is not None: frames = frames[0:max_frame,:,:] height, width, _ = frames[0].shape # detected_poses = [dwprocessor(frm) for frm in tqdm(frames, desc="DWPose")] detected_poses = [dwprocessor(frm) for frm in frames] dwprocessor.release_memory() return detected_poses, height, width, frames def resize_and_pad(img, max_size): img_new = np.zeros((max_size, max_size, 3)).astype('uint8') imh, imw = img.shape[0], img.shape[1] half = max_size // 2 if imh > imw: imh_new = max_size imw_new = int(round(imw/imh * imh_new)) half_w = imw_new // 2 rb, re = 0, max_size cb = half-half_w ce = cb + imw_new else: imw_new = max_size imh_new = int(round(imh/imw * imw_new)) half_h = imh_new // 2 cb, ce = 0, max_size rb = half-half_h re = rb + imh_new img_resize = cv2.resize(img, (imw_new, imh_new)) img_new[rb:re,cb:ce,:] = img_resize return img_new def resize_and_pad_param(imh, imw, max_size): half = max_size // 2 if imh > imw: imh_new = max_size imw_new = int(round(imw/imh * imh_new)) half_w = imw_new // 2 rb, re = 0, max_size cb = half-half_w ce = cb + imw_new else: imw_new = max_size imh_new = int(round(imh/imw * imw_new)) imh_new = max_size half_h = imh_new // 2 cb, ce = 0, max_size rb = half-half_h re = rb + imh_new return imh_new, imw_new, rb, re, cb, ce def get_pose_params(detected_poses, max_size): print('get_pose_params...') # pose rescale w_min_all, w_max_all, h_min_all, h_max_all = [], [], [], [] mid_all = [] for num, detected_pose in enumerate(detected_poses): detected_poses[num]['num'] = num candidate_body = detected_pose['bodies']['candidate'] score_body = detected_pose['bodies']['score'] candidate_face = detected_pose['faces'] score_face = detected_pose['faces_score'] candidate_hand = detected_pose['hands'] score_hand = detected_pose['hands_score'] # 选取置信度最高的face if candidate_face.shape[0] > 1: index = 0 candidate_face = candidate_face[index] score_face = score_face[index] detected_poses[num]['faces'] = candidate_face.reshape(1, candidate_face.shape[0], candidate_face.shape[1]) detected_poses[num]['faces_score'] = score_face.reshape(1, score_face.shape[0]) else: candidate_face = candidate_face[0] score_face = score_face[0] # 选取置信度最高的body if score_body.shape[0] > 1: tmp_score = [] for k in range(0, score_body.shape[0]): tmp_score.append(score_body[k].mean()) index = np.argmax(tmp_score) candidate_body = candidate_body[index*18:(index+1)*18,:] score_body = score_body[index] score_hand = score_hand[(index*2):(index*2+2),:] candidate_hand = candidate_hand[(index*2):(index*2+2),:,:] else: score_body = score_body[0] all_pose = np.concatenate((candidate_body, candidate_face)) all_score = np.concatenate((score_body, score_face)) all_pose = all_pose[all_score>0.8] body_pose = np.concatenate((candidate_body,)) mid_ = body_pose[1, 0] face_pose = candidate_face hand_pose = candidate_hand h_min, h_max = np.min(face_pose[:,1]), np.max(body_pose[:7,1]) h_ = h_max - h_min mid_w = mid_ w_min = mid_w - h_ // 2 w_max = mid_w + h_ // 2 w_min_all.append(w_min) w_max_all.append(w_max) h_min_all.append(h_min) h_max_all.append(h_max) mid_all.append(mid_w) w_min = np.min(w_min_all) w_max = np.max(w_max_all) h_min = np.min(h_min_all) h_max = np.max(h_max_all) mid = np.mean(mid_all) print(mid) margin_ratio = 0.25 h_margin = (h_max-h_min)*margin_ratio h_min = max(h_min-h_margin*0.65, 0) h_max = min(h_max+h_margin*0.5, 1) h_new = h_max - h_min h_min_real = int(h_min*height) h_max_real = int(h_max*height) mid_real = int(mid*width) height_new = h_max_real-h_min_real+1 width_new = height_new w_min_real = mid_real - height_new // 2 w_max_real = w_min_real + width_new w_min = w_min_real / width w_max = w_max_real / width print(width_new, height_new) imh_new, imw_new, rb, re, cb, ce = resize_and_pad_param(height_new, width_new, max_size) res = {'draw_pose_params': [imh_new, imw_new, rb, re, cb, ce], 'pose_params': [w_min, w_max, h_min, h_max], 'video_params': [h_min_real, h_max_real, w_min_real, w_max_real], } return res def save_pose_params_item(input_items): detected_pose, pose_params, draw_pose_params, save_dir = input_items w_min, w_max, h_min, h_max = pose_params num = detected_pose['num'] candidate_body = detected_pose['bodies']['candidate'] candidate_face = detected_pose['faces'][0] candidate_hand = detected_pose['hands'] candidate_body[:,0] = (candidate_body[:,0]-w_min)/(w_max-w_min) candidate_body[:,1] = (candidate_body[:,1]-h_min)/(h_max-h_min) candidate_face[:,0] = (candidate_face[:,0]-w_min)/(w_max-w_min) candidate_face[:,1] = (candidate_face[:,1]-h_min)/(h_max-h_min) candidate_hand[:,:,0] = (candidate_hand[:,:,0]-w_min)/(w_max-w_min) candidate_hand[:,:,1] = (candidate_hand[:,:,1]-h_min)/(h_max-h_min) detected_pose['bodies']['candidate'] = candidate_body detected_pose['faces'] = candidate_face.reshape(1, candidate_face.shape[0], candidate_face.shape[1]) detected_pose['hands'] = candidate_hand detected_pose['draw_pose_params'] = draw_pose_params np.save(save_dir+'/'+str(num)+'.npy', detected_pose) def save_pose_params(detected_poses, pose_params, draw_pose_params, ori_video_path): save_dir = ori_video_path.replace('original_videos', 'image_audio_features/pose/') if not os.path.exists(save_dir): os.makedirs(save_dir) input_list = [] for i, detected_pose in enumerate(detected_poses): input_list.append([detected_pose, pose_params, draw_pose_params, save_dir]) pool = ThreadPool(8) pool.map(save_pose_params_item, input_list) pool.close() pool.join() def save_processed_video(ori_frames, video_params, ori_video_path, max_size): save_path = ori_video_path.replace('original_videos', 'processed/video/') save_dir = os.path.dirname(save_path) if not os.path.exists(save_dir): os.makedirs(save_dir) h_min_real, h_max_real, w_min_real, w_max_real = video_params video_frame_crop = [] for img in ori_frames: img = img[h_min_real:h_max_real,w_min_real:w_max_real,:] img = resize_and_pad(img, max_size=max_size) video_frame_crop.append(img) save_video_from_cv2_list(video_frame_crop, save_path, fps=24.0, rgb2bgr=True) return video_frame_crop def save_audio(ori_video_path, sub_task): save_path = ori_video_path.replace('original_videos', 'processed/audio/') save_dir = os.path.dirname(save_path) save_path = save_path + '.wav' if not os.path.exists(save_dir): os.makedirs(save_dir) ori_video_path = ori_video_path.replace(sub_task, sub_task+'_24fps') audio_clip = AudioFileClip(ori_video_path) audio_clip.write_audiofile(save_path) def draw_pose_video(pose_params_path, save_path, max_size, ori_frames=None): pose_files = os.listdir(pose_params_path) # 生成Pose图cd pro output_pose_img = [] for i in range(0, len(pose_files)): pose_params_path_tmp = pose_params_path + '/' + str(i) + '.npy' detected_pose = np.load(pose_params_path_tmp, allow_pickle=True).tolist() imh_new, imw_new, rb, re, cb, ce = detected_pose['draw_pose_params'] im = draw_pose(detected_pose, imh_new, imw_new, ref_w=800) im = np.transpose(np.array(im),(1,2,0)) img_new = np.zeros((max_size, max_size, 3)).astype('uint8') img_new[rb:re,cb:ce,:] = im if ori_frames is not None: img_new = img_new * 0.6 + ori_frames[i] * 0.4 img_new = img_new.astype('uint8') output_pose_img.append(img_new) output_pose_img = np.stack(output_pose_img) save_video_from_cv2_list(output_pose_img, save_path, fps=24.0, rgb2bgr=True) print('save to ' + save_path) visualization = False for sub_task in tasks: ori_list = os.listdir(base_dir+sub_task)[start:end] mp4_list = ori_list new_dir = base_dir+sub_task+'_24fps' if not os.path.exists(new_dir): os.makedirs(new_dir) index = 1 for i, mp4_file in enumerate(mp4_list): ori_video_path = base_dir+sub_task+'/'+mp4_file if ori_video_path[-3:]=='mp4' or ori_video_path[-3:] =='MOV': try: # 转换祯率 ori_video_path_new = ori_video_path.replace(sub_task, sub_task+'_24fps') if '.MOV' in ori_video_path_new: ori_video_path_new.replace('.MOV', '.mp4') convert_fps(ori_video_path, ori_video_path_new) print([index+start, ori_video_path, start, end]) # 提取Pose detected_poses, height, width, ori_frames = get_video_pose(ori_video_path_new, max_frame=None) print(height, width) # 提取相关参数 res_params = get_pose_params(detected_poses, MAX_SIZE) # 存储Pose参数 save_pose_params(detected_poses, res_params['pose_params'], res_params['draw_pose_params'], ori_video_path) # 存储截取视频 video_frame_crop = save_processed_video(ori_frames, res_params['video_params'], ori_video_path, MAX_SIZE) # 存储音频 save_audio(ori_video_path, sub_task) index += 1 if visualization: # 绘制pose图 pose_params_path = ori_video_path.replace('original_videos', 'image_audio_features/pose') save_path = "./vis_pose_results/" + os.path.basename(ori_video_path) draw_pose_video(pose_params_path, save_path, ori_frames=video_frame_crop) except: print(["extract crash!", index+start, ori_video_path, start, end]) continue print(["All Finished", sub_task, start, end])