# -*- coding: utf-8 -*- # This script is borrowed and extended from https://github.com/mkocabas/VIBE/blob/master/demo.py and https://github.com/nkolot/SPIN/blob/master/demo.py # Max-Planck-Gesellschaft zur Förderung der Wissenschaften e.V. (MPG) is # holder of all proprietary rights on this computer program. # You can only use this computer program if you have closed # a license agreement with MPG or you get the right to use the computer # program from someone who is authorized to grant you that right. # Any use of the computer program without a valid license is prohibited and # liable to prosecution. # # Copyright©2019 Max-Planck-Gesellschaft zur Förderung # der Wissenschaften e.V. (MPG). acting on behalf of its Max Planck Institute # for Intelligent Systems. All rights reserved. # # Contact: ps-license@tuebingen.mpg.de import matplotlib import platform import warnings if platform.system() == 'Windows': matplotlib.use('TkAgg') from copyreg import pickle import enum import os import copy import platform if platform.system() == "Linux": os.environ['PYOPENGL_PLATFORM'] = 'egl' os.chdir(os.path.join(os.path.dirname(__file__),'..')) import sys # sys.path.insert( # 0,os.path.join(os.path.dirname(__file__),'..') # ) sys.path.append(os.path.join(os.path.dirname(__file__),'..')) import pickle as pkle import cv2 import time import json import shutil import torch import joblib import argparse import numpy as np from tqdm import tqdm from torch.utils.data import DataLoader import os.path as osp from matplotlib.image import imsave from skimage.transform import resize from torchvision.transforms import Normalize from collections import OrderedDict from pymaf_core.cfgs import cfg, parse_args from pymaf_core import path_config, constants # from cfgs import cfg, parse_args # import path_config, constants from models import hmr, pymaf_net, SMPL from models.smpl import get_partial_smpl from datasets.inference import Inference from utils.renderer import PyRenderer from utils.imutils import crop from utils.demo_utils import ( download_url, convert_crop_cam_to_orig_img, video_to_images, images_to_video, ) from utils.geometry import convert_to_full_img_cam from openpifpaf import decoder as ppdecoder from openpifpaf import network as ppnetwork from openpifpaf.predictor import Predictor from openpifpaf.stream import Stream torch.backends.cudnn.enabled = False MIN_NUM_FRAMES = 1 def prepare_rendering_results(person_data, nframes): frame_results = [{} for _ in range(nframes)] for idx, frame_id in enumerate(person_data['frame_ids']): person_id = person_data['person_ids'][idx], frame_results[frame_id][person_id] = { 'verts': person_data['verts'][idx], 'smplx_verts': person_data['smplx_verts'][idx] if 'smplx_verts' in person_data else None, 'cam': person_data['orig_cam'][idx], 'cam_t': person_data['orig_cam_t'][idx] if 'orig_cam_t' in person_data else None, # 'cam': person_data['pred_cam'][idx], } # naive depth ordering based on the scale of the weak perspective camera for frame_id, frame_data in enumerate(frame_results): # sort based on y-scale of the cam in original image coords sort_idx = np.argsort([v['cam'][1] for k,v in frame_data.items()]) frame_results[frame_id] = OrderedDict( {list(frame_data.keys())[i]:frame_data[list(frame_data.keys())[i]] for i in sort_idx} ) return frame_results def run_demo(args): device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') if args.image_folder is None: video_file = args.vid_file # ========= [Optional] download the youtube video ========= # if video_file.startswith('https://www.youtube.com'): print(f'Donwloading YouTube video \"{video_file}\"') video_file = download_url(video_file, '/tmp') if video_file is None: exit('Youtube url is not valid!') print(f'YouTube Video has been downloaded to {video_file}...') if not os.path.isfile(video_file): exit(f'Input video \"{video_file}\" does not exist!') output_path = os.path.join(args.output_folder, os.path.basename(video_file).replace('.mp4', '')) image_folder, num_frames, img_shape = video_to_images(video_file, return_info=True) else: image_folder = args.image_folder num_frames = len(os.listdir(image_folder)) img_shape = cv2.imread(osp.join(image_folder, os.listdir(image_folder)[0])).shape output_path = os.path.join(args.output_folder, osp.split(image_folder)[-1]) os.makedirs(output_path, exist_ok=True) print(f'Input video number of frames {num_frames}') total_time = time.time() args.device = device args.pin_memory = True if torch.cuda.is_available() else False # pifpaf person detection pp_det_file_path = os.path.join(output_path, 'pp_det_results.pkl') pp_args = copy.deepcopy(args) pp_args.force_complete_pose = True ppdecoder.configure(pp_args) ppnetwork.Factory.configure(pp_args) ppnetwork.Factory.checkpoint = pp_args.detector_checkpoint Predictor.configure(pp_args) Stream.configure(pp_args) Predictor.batch_size = pp_args.detector_batch_size if pp_args.detector_batch_size > 1: Predictor.long_edge = 1000 Predictor.loader_workers = 1 predictor = Predictor() if args.vid_file is not None: capture = Stream(args.vid_file, preprocess=predictor.preprocess) capture = predictor.dataset(capture) elif args.image_folder is not None: image_file_names = sorted([ osp.join(image_folder, x) for x in os.listdir(image_folder) if x.endswith('.png') or x.endswith('.jpg') ]) capture = predictor.images(image_file_names) tracking_results = {} print('Running openpifpaf for person detection...') for preds, _, meta in tqdm(capture, total=num_frames // args.detector_batch_size): # preds = [preds[0]] for pid, ann in enumerate(preds): if ann.score > args.detection_threshold: frame_i = meta['frame_i'] - 1 if 'frame_i' in meta else meta['dataset_index'] file_name = meta['file_name'] if 'file_name' in meta else image_folder person_id = file_name.split('/')[-1].split('.')[0] + '_f' + str(frame_i) + '_p' + str(pid) det_wb_kps = ann.data det_face_kps = det_wb_kps[23:91] # tracking_results[person_id] = { 'frames': [frame_i], # 'predictions': [ann.json_data() for ann in preds] 'joints2d': [det_wb_kps[:17]], 'joints2d_lhand': [det_wb_kps[91:112]], 'joints2d_rhand': [det_wb_kps[112:133]], 'joints2d_face': [np.concatenate([det_face_kps[17:], det_face_kps[:17]])], } if 1: from collections import defaultdict f_dict=defaultdict(list) p_dict=defaultdict(dict) for key in tracking_results.keys(): p=key.split('_')[-1] f=key.split('_')[-2] f_dict[f].append(p) p_dict[f][p]=key # if p in f_dict[f]: for f,p_list in f_dict.items(): max_x=None if len(p_list)>1: for p in p_list: key=p_dict[f][p] det_face_kps=tracking_results[key]['joints2d_face'][0] face_mean_x=np.mean(det_face_kps,axis=0)[0] if max_x is None or face_mean_x>max_x: max_x=face_mean_x if max_x is not None and face_mean_x