From 99da02485b1b0bd17bf4ac3f1952fc1ed6ad8b2a Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sat, 14 May 2022 01:42:21 +0800 Subject: [PATCH 01/21] perf args --- args.py | 19 ++++++ main.py | 95 ++++++++++++++------------ models.py | 14 ++++ test.py | 197 +++++++++++++++++++++++++++++++++++++++++++++++------- 4 files changed, 261 insertions(+), 64 deletions(-) create mode 100644 args.py diff --git a/args.py b/args.py new file mode 100644 index 0000000..b256ea1 --- /dev/null +++ b/args.py @@ -0,0 +1,19 @@ +import argparse + +parser = argparse.ArgumentParser() +parser.add_argument('--debug', action='store_true') +parser.add_argument('--extend_movement', type=float) +parser.add_argument('--input', type=str, default='cam') +parser.add_argument('--character', type=str, default='y') +parser.add_argument('--output_dir', type=str) +parser.add_argument('--output_webcam', type=str) +parser.add_argument('--output_size', type=str, default='256x256') +parser.add_argument('--debug_input', action='store_true') +parser.add_argument('--perf', action='store_true') +parser.add_argument('--skip_model', action='store_true') +parser.add_argument('--ifm', type=str) +parser.add_argument('--anime4k', action='store_true') +args = parser.parse_args() +args.output_w = int(args.output_size.split('x')[0]) +args.output_h = int(args.output_size.split('x')[1]) +if args.output_webcam is None and args.output_dir is None: args.debug = True \ No newline at end of file diff --git a/main.py b/main.py index 6608641..b01e4cb 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,3 @@ -import argparse - import cv2 import torch import pyvirtualcam @@ -26,21 +24,7 @@ from pyanime4k import ac from tha2.mocap.ifacialmocap_constants import * -parser = argparse.ArgumentParser() -parser.add_argument('--debug', action='store_true') -parser.add_argument('--extend_movement', type=float) -parser.add_argument('--input', type=str, default='cam') -parser.add_argument('--character', type=str, default='y') -parser.add_argument('--output_dir', type=str) -parser.add_argument('--output_webcam', type=str) -parser.add_argument('--output_size', type=str, default='256x256') -parser.add_argument('--debug_input', action='store_true') -parser.add_argument('--ifm', type=str) -parser.add_argument('--anime4k', action='store_true') -args = parser.parse_args() -args.output_w = int(args.output_size.split('x')[0]) -args.output_h = int(args.output_size.split('x')[1]) -if args.output_webcam is None and args.output_dir is None: args.debug = True +from args import args device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') @@ -150,10 +134,12 @@ class ClientProcess(Process): @torch.no_grad() def main(): - model = TalkingAnimeLight().to(device) - model = model.eval() - model = model - print("Pretrained Model Loaded") + model = None + if not args.skip_model: + model = TalkingAnimeLight().to(device) + model = model.eval() + model = model + print("Pretrained Model Loaded") img = Image.open(f"character/{args.character}.png") wRatio = img.size[0] / 256 img = img.resize((256, int(img.size[1] / wRatio))) @@ -235,7 +221,7 @@ def main(): pose_queue = [] blender_data = create_default_blender_data() - tic=0 + tic1 = 0 print("Ready. Close this console to exit.") @@ -244,21 +230,24 @@ def main(): # input_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # results = facemesh.process(input_frame) + if args.perf: + print('===') + tic = time.perf_counter() if args.debug_input: mouth_eye_vector[0, :] = 0 pose_vector[0, :] = 0 - mouth_eye_vector[0, 2] = math.sin(time.perf_counter()*3) - mouth_eye_vector[0, 3] = math.sin(time.perf_counter()*3) + mouth_eye_vector[0, 2] = math.sin(time.perf_counter() * 3) + mouth_eye_vector[0, 3] = math.sin(time.perf_counter() * 3) mouth_eye_vector[0, 14] = 0 - mouth_eye_vector[0, 25] = math.sin(time.perf_counter()*2.2)*0.2 - mouth_eye_vector[0, 26] = math.sin(time.perf_counter()*3.5)*0.8 + mouth_eye_vector[0, 25] = math.sin(time.perf_counter() * 2.2) * 0.2 + mouth_eye_vector[0, 26] = math.sin(time.perf_counter() * 3.5) * 0.8 - pose_vector[0, 0] = math.sin(time.perf_counter()*1.1) - pose_vector[0, 1] = math.sin(time.perf_counter()*1.2) - pose_vector[0, 2] = math.sin(time.perf_counter()*1.5) + pose_vector[0, 0] = math.sin(time.perf_counter() * 1.1) + pose_vector[0, 1] = math.sin(time.perf_counter() * 1.2) + pose_vector[0, 2] = math.sin(time.perf_counter() * 1.5) elif args.ifm is not None: @@ -346,16 +335,32 @@ def main(): pose_vector[0, 0] = (x_angle - 1.5) * 1.6 pose_vector[0, 1] = y_angle * 2.0 # temp weight pose_vector[0, 2] = (z_angle + 1.5) * 2 # temp weight - - output_image = model(input_image, mouth_eye_vector, pose_vector) - postprocessed_image = postprocessing_image(output_image.cpu()) + if args.perf: + print("input", time.perf_counter() - tic) + tic = time.perf_counter() + if model is None: + output_image=input_image + else: + output_image = model(input_image, mouth_eye_vector, pose_vector) + if args.perf: + torch.cuda.synchronize() + print("model", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = output_image.cpu() + if args.perf: + print("cpu()", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = postprocessing_image(postprocessed_image) + if args.perf: + print("postprocess", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() if extra_image is not None: postprocessed_image = cv2.vconcat([postprocessed_image, extra_image]) - k_scale=1 - rotate_angle=0 - dx=0 - dy=0 + k_scale = 1 + rotate_angle = 0 + dx = 0 + dy = 0 if args.extend_movement is not None: k_scale = position_vector[2] * math.sqrt(args.extend_movement) + 1 rotate_angle = -position_vector[0] * 40 * args.extend_movement @@ -370,6 +375,10 @@ def main(): rm, (args.output_w, args.output_h)) + if args.perf: + print("extendmovement", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + if args.anime4k: alpha_channel = postprocessed_image[:, :, 3] alpha_channel = cv2.resize(alpha_channel, None, fx=2, fy=2) @@ -383,15 +392,17 @@ def main(): postprocessed_image = a.save_image_to_numpy() postprocessed_image = cv2.merge((postprocessed_image, alpha_channel)) postprocessed_image = cv2.cvtColor(postprocessed_image, cv2.COLOR_BGRA2RGBA) - + if args.perf: + print("anime4k", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() if args.debug: output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) # resized_frame = cv2.resize(output_frame, (np.min(debug_image.shape[:2]), np.min(debug_image.shape[:2]))) # output_frame = np.concatenate([debug_image, resized_frame], axis=1) toc = time.perf_counter() - fps = 1 / (toc - tic) - tic = toc - cv2.putText(output_frame, str('%.1f' % fps),(0,16),cv2.FONT_HERSHEY_PLAIN,1,(0,255,0),1) + fps = 1 / (toc - tic1) + tic1 = toc + cv2.putText(output_frame, str('%.1f' % fps), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) # cv2.imshow("camera", debug_image) cv2.waitKey(1) @@ -404,7 +415,9 @@ def main(): result_image = cv2.cvtColor(result_image, cv2.COLOR_RGBA2RGB) cam.send(result_image) cam.sleep_until_next_frame() - + if args.perf: + print("output", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() if __name__ == '__main__': diff --git a/models.py b/models.py index bc17477..e7bcf07 100644 --- a/models.py +++ b/models.py @@ -1,7 +1,10 @@ +import time + import torch.nn as nn from tha2.poser.modes.mode_20 import load_face_morpher, load_face_rotater, load_combiner +from args import args class TalkingAnimeLight(nn.Module): def __init__(self): @@ -12,10 +15,21 @@ class TalkingAnimeLight(nn.Module): def forward(self, image, mouth_eye_vector, pose_vector): x = image.clone() + if args.perf: + tic=time.perf_counter() mouth_eye_morp_image = self.face_morpher(image[:, :, 32:224, 32:224], mouth_eye_vector) + if args.perf: + print(" - face_morpher",(time.perf_counter()-tic)*1000) + tic=time.perf_counter() x[:, :, 32:224, 32:224] = mouth_eye_morp_image rotate_image = self.two_algo_face_rotator(x, pose_vector)[:2] + if args.perf: + print(" - rotator",(time.perf_counter()-tic)*1000) + tic=time.perf_counter() output_image = self.combiner(rotate_image[0], rotate_image[1], pose_vector) + if args.perf: + print(" - combiner",(time.perf_counter()-tic)*1000) + tic=time.perf_counter() return output_image diff --git a/test.py b/test.py index 51e7d3f..da42f49 100644 --- a/test.py +++ b/test.py @@ -1,27 +1,65 @@ -from pyanime4k import ac -import pyanime4k - -parameters = ac.Parameters() -# enable HDN for ACNet -parameters.HDN = True - -a = ac.AC( - type=ac.ProcessorType.CPU_ACNet, -) -a.set_arguments(parameters) +# from pyanime4k import ac +# import pyanime4k +# +# parameters = ac.Parameters() +# # enable HDN for ACNet +# parameters.HDN = True +# +# a = ac.AC( +# type=ac.ProcessorType.CPU_ACNet, +# ) +# a.set_arguments(parameters) import cv2 +# +# img = cv2.imread("character/test41.png") +# +# a.load_image_from_numpy(img,input_type=ac.AC_INPUT_BGR) +# +# a.get_processor_info() +# +# # start processing +# a.process() +# +# a.show_image() -img = cv2.imread("character/test41.png") - -a.load_image_from_numpy(img,input_type=ac.AC_INPUT_BGR) - -a.get_processor_info() - -# start processing -a.process() - -a.show_image() - +# import numpy as np +# import zlib +# import bz2 +# import lzma +# import time +# +# postprocessed_image=np.load('out.npy') +# tic=time.perf_counter() +# res=None +# for i in range(100): +# res=zlib.compress(postprocessed_image) +# print("zlib", len(res),(time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# for i in range(100): +# zlib.decompress(res) +# print("zlib", len(res),(time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# for i in range(100): +# res=bz2.compress(postprocessed_image) +# print("bz2",len(res), (time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# for i in range(100): +# bz2.decompress(res) +# print("bz2", len(res),(time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# for i in range(100): +# res=lzma.compress(postprocessed_image) +# print("lzma",len(res), (time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# for i in range(100): +# lzma.decompress(res) +# print("lzma", len(res),(time.perf_counter() - tic) * 1000) +# tic = time.perf_counter() +# +# +# output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) +# cv2.imshow("frame", output_frame) +# cv2.waitKey(100000) # preview upscaled image # img=a.save_image_to_numpy() # @@ -42,4 +80,117 @@ a.show_image() # [1,2,3,4], # ] # -# print(cv2.merge((np.array(rgb),np.array(a)))) \ No newline at end of file +# print(cv2.merge((np.array(rgb),np.array(a)))) + + +from multiprocessing import Value, Process, Queue +import queue +import socket +import errno +import time +import tha2.poser.modes.mode_20_wx +from tha2.mocap.ifacialmocap_constants import * + +ifm='192.168.31.182:49983' + + + +class ClientProcess(Process): + def __init__(self): + super().__init__() + self.queue = Queue() + self.should_terminate = Value('b', False) + self.address = ifm.split(':')[0] + self.port = int(ifm.split(':')[1]) + self.perf_time = 0 + self.ifm_converter = tha2.poser.modes.mode_20_wx.create_ifacialmocap_pose_converter() + self.a_min=None + self.a_max=None + + def run(self): + + udpClntSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + data = "iFacialMocap_sahuasouryya9218sauhuiayeta91555dy3719" + + data = data.encode('utf-8') + + udpClntSock.sendto(data, (self.address, self.port)) + + self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.socket.setblocking(False) + self.socket.bind(("", self.port)) + self.socket.settimeout(0.1) + while True: + if self.should_terminate.value: + break + try: + socket_bytes = self.socket.recv(8192) + except socket.error as e: + err = e.args[0] + if err == errno.EAGAIN or err == errno.EWOULDBLOCK or err == 'timed out': + continue + else: + raise e + socket_string = socket_bytes.decode("utf-8") + # print(socket_string) + + # blender_data = json.loads(socket_string) + data = self.convert_from_blender_data(socket_string) + data=self.ifm_converter.convert(data) + # print(data) + if(self.a_max is None): + self.a_max=[x for x in data] + else: + self.a_max=[max(data[i],self.a_max[i]) for i in range(len(data))] + if(self.a_min is None): + self.a_min=[x for x in data] + else: + self.a_min=[min(data[i],self.a_min[i]) for i in range(len(data))] + print([[self.a_min[i],self.a_max[i]] for i in range(len(data))]) + cur_time = time.perf_counter() + fps = 1 / (cur_time - self.perf_time) + self.perf_time = cur_time + # print(fps) + try: + self.queue.put_nowait(data) + except queue.Full: + pass + self.queue.close() + self.socket.close() + @staticmethod + def convert_from_blender_data(blender_data): + data = {} + + for item in blender_data.split('|'): + if item.find('#') != -1: + k, arr = item.split('#') + arr = [float(n) for n in arr.split(',')] + data[k.replace("_L", "Left").replace("_R", "Right")] = arr + elif item.find('-') != -1: + k, v = item.split("-") + data[k.replace("_L", "Left").replace("_R", "Right")] = float(v) / 100 + + to_rad = 57.3 + data[HEAD_BONE_X] = data["=head"][0] / to_rad + data[HEAD_BONE_Y] = data["=head"][1] / to_rad + data[HEAD_BONE_Z] = data["=head"][2] / to_rad + data[HEAD_BONE_QUAT] = [data["=head"][3], data["=head"][4], data["=head"][5], 1] + # print(data[HEAD_BONE_QUAT][2],min(data[EYE_BLINK_LEFT],data[EYE_BLINK_RIGHT])) + data[RIGHT_EYE_BONE_X] = data["rightEye"][0] / to_rad + data[RIGHT_EYE_BONE_Y] = data["rightEye"][1] / to_rad + data[RIGHT_EYE_BONE_Z] = data["rightEye"][2] / to_rad + data[LEFT_EYE_BONE_X] = data["leftEye"][0] / to_rad + data[LEFT_EYE_BONE_Y] = data["leftEye"][1] / to_rad + data[LEFT_EYE_BONE_Z] = data["leftEye"][2] / to_rad + + return data + + +if __name__ == '__main__': + client_process = ClientProcess() + client_process.daemon = True + client_process.start() + + while True: + pass \ No newline at end of file From 0e0ffc88f360b736be5225f4412fc7058dee9e00 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sat, 14 May 2022 06:44:20 +0800 Subject: [PATCH 02/21] test something --- main.py | 92 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/main.py b/main.py index b01e4cb..fa1cf75 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ import queue import socket import time import math +from collections import OrderedDict from multiprocessing import Value, Process, Queue import pyanime4k @@ -26,7 +27,7 @@ from tha2.mocap.ifacialmocap_constants import * from args import args -device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu') +device = torch.device('cuda') if torch.cuda.is_available() and not args.skip_model else torch.device('cpu') def create_default_blender_data(): @@ -53,7 +54,7 @@ def create_default_blender_data(): return data -class ClientProcess(Process): +class IFMClientProcess(Process): def __init__(self): super().__init__() self.queue = Queue() @@ -156,7 +157,7 @@ def main(): if not args.debug_input: if args.ifm is not None: - client_process = ClientProcess() + client_process = IFMClientProcess() client_process.daemon = True client_process.start() ifm_converter = tha2.poser.modes.mode_20_wx.create_ifacialmocap_pose_converter() @@ -209,6 +210,8 @@ def main(): mouth_eye_vector = torch.empty(1, 27) pose_vector = torch.empty(1, 3) + mouth_eye_vector_c = [0.0]*27 + pose_vector_c = [0.0]*3 # input_image = input_image.half() # mouth_eye_vector = mouth_eye_vector.half() @@ -223,6 +226,13 @@ def main(): blender_data = create_default_blender_data() tic1 = 0 + vector_hash=None + prev_hash=None + changed_count=0 + missed_count=0 + tot_count=0 + model_cache=OrderedDict() + print("Ready. Close this console to exit.") while True: @@ -234,20 +244,21 @@ def main(): print('===') tic = time.perf_counter() if args.debug_input: - mouth_eye_vector[0, :] = 0 - pose_vector[0, :] = 0 + mouth_eye_vector_c = [0.0]*27 + pose_vector_c = [0.0]*3 - mouth_eye_vector[0, 2] = math.sin(time.perf_counter() * 3) - mouth_eye_vector[0, 3] = math.sin(time.perf_counter() * 3) + mouth_eye_vector_c[2] = math.sin(time.perf_counter() * 3) + mouth_eye_vector_c[3] = math.sin(time.perf_counter() * 3) - mouth_eye_vector[0, 14] = 0 + mouth_eye_vector_c[14] = 0 - mouth_eye_vector[0, 25] = math.sin(time.perf_counter() * 2.2) * 0.2 - mouth_eye_vector[0, 26] = math.sin(time.perf_counter() * 3.5) * 0.8 + mouth_eye_vector_c[25] = math.sin(time.perf_counter() * 2.2) * 0.2 + mouth_eye_vector_c[26] = math.sin(time.perf_counter() * 3.5) * 0.8 + + pose_vector_c[0] = math.sin(time.perf_counter() * 1.1) + pose_vector_c[1] = math.sin(time.perf_counter() * 1.2) + pose_vector_c[2] = math.sin(time.perf_counter() * 1.5) - pose_vector[0, 0] = math.sin(time.perf_counter() * 1.1) - pose_vector[0, 1] = math.sin(time.perf_counter() * 1.2) - pose_vector[0, 2] = math.sin(time.perf_counter() * 1.5) elif args.ifm is not None: @@ -258,7 +269,7 @@ def main(): new_blender_data = client_process.queue.get_nowait() blender_data = new_blender_data except queue.Empty: - pass + continue ifacialmocap_pose_converted = ifm_converter.convert(blender_data) @@ -281,11 +292,15 @@ def main(): # - ifacialmocap_pose[EYE_LOOK_DOWN_RIGHT] # + ifacialmocap_pose[EYE_LOOK_DOWN_LEFT]) / 2.0 / 0.75 - position_vector = blender_data[HEAD_BONE_QUAT] + mouth_eye_vector_c = [0.0]*27 + pose_vector_c = [0.0]*3 for i in range(12, 39): - mouth_eye_vector[0, i - 12] = ifacialmocap_pose_converted[i] + mouth_eye_vector_c[i - 12] = ifacialmocap_pose_converted[i] for i in range(39, 42): - pose_vector[0, i - 39] = ifacialmocap_pose_converted[i] + pose_vector_c[i - 39] = ifacialmocap_pose_converted[i] + + position_vector = blender_data[HEAD_BONE_QUAT] + else: ret, frame = cap.read() @@ -321,23 +336,45 @@ def main(): y_angle = np_pose[6] z_angle = np_pose[7] - mouth_eye_vector[0, :] = 0 - pose_vector[0, :] = 0 + mouth_eye_vector_c = [0.0] * 27 + pose_vector_c = [0.0] * 3 - mouth_eye_vector[0, 2] = eye_l_h_temp - mouth_eye_vector[0, 3] = eye_r_h_temp + mouth_eye_vector_c[2] = eye_l_h_temp + mouth_eye_vector_c[3] = eye_r_h_temp - mouth_eye_vector[0, 14] = mouth_ratio * 1.5 + mouth_eye_vector_c[14] = mouth_ratio * 1.5 - mouth_eye_vector[0, 25] = eye_y_ratio - mouth_eye_vector[0, 26] = eye_x_ratio + mouth_eye_vector_c[25] = eye_y_ratio + mouth_eye_vector_c[26] = eye_x_ratio + + pose_vector_c[0] = (x_angle - 1.5) * 1.6 + pose_vector_c[1] = y_angle * 2.0 # temp weight + pose_vector_c[2] = (z_angle + 1.5) * 2 # temp weight - pose_vector[0, 0] = (x_angle - 1.5) * 1.6 - pose_vector[0, 1] = y_angle * 2.0 # temp weight - pose_vector[0, 2] = (z_angle + 1.5) * 2 # temp weight if args.perf: print("input", time.perf_counter() - tic) tic = time.perf_counter() + + hash_arr=mouth_eye_vector_c + hash_arr.extend(pose_vector_c) + vector_hash=hash(tuple(hash_arr)) + tot_count+=1 + if vector_hash==prev_hash: continue + # print("hash", vector_hash) + if vector_hash!=prev_hash: changed_count+=1 + prev_hash=vector_hash + if model_cache.get(vector_hash) is None: + model_cache[vector_hash]=True + missed_count+=1 + # + # print('changed ratio',changed_count/tot_count*100) + # print('missed ratio',missed_count/tot_count*100) + + for i in range(27): + mouth_eye_vector[0,i]=mouth_eye_vector_c[i] + for i in range(3): + pose_vector[0,i]=pose_vector_c[i] + torch.cuda.synchronize() if model is None: output_image=input_image else: @@ -403,6 +440,7 @@ def main(): fps = 1 / (toc - tic1) tic1 = toc cv2.putText(output_frame, str('%.1f' % fps), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + # cv2.putText(output_frame, str('%.1f' % (missed_count/changed_count*100)), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) # cv2.imshow("camera", debug_image) cv2.waitKey(1) From a9f085ba23b57976670e332bbad80b8212168a1e Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sat, 14 May 2022 20:47:00 +0800 Subject: [PATCH 03/21] split render and extend+output --- main.py | 158 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 60 deletions(-) diff --git a/main.py b/main.py index fa1cf75..6e10749 100644 --- a/main.py +++ b/main.py @@ -90,7 +90,6 @@ class IFMClientProcess(Process): raise e socket_string = socket_bytes.decode("utf-8") # print(socket_string) - # blender_data = json.loads(socket_string) data = self.convert_from_blender_data(socket_string) # cur_time = time.perf_counter() @@ -133,14 +132,69 @@ class IFMClientProcess(Process): return data +class ModelClientProcess(Process): + def __init__(self, input_image): + super().__init__() + self.should_terminate = Value('b', False) + self.updated=Value('b', False) + self.data = None + self.input_image = input_image + self.output_queue=Queue() + self.input_queue=Queue() + + def run(self): + model = None + if not args.skip_model: + model = TalkingAnimeLight().to(device) + model = model.eval() + model = model + print("Pretrained Model Loaded") + + mouth_eye_vector = torch.empty(1, 27) + pose_vector = torch.empty(1, 3) + + input_image = self.input_image.to(device) + mouth_eye_vector = mouth_eye_vector.to(device) + pose_vector = pose_vector.to(device) + + while True: + input = None + try: + while not self.input_queue.empty(): + input = self.input_queue.get_nowait() + except queue.Empty: + continue + if input is None: continue + + for i in range(27): + mouth_eye_vector[0, i] = input[i] + for i in range(3): + pose_vector[0, i] = input[i+27] + if model is None: + output_image = input_image + else: + output_image = model(input_image, mouth_eye_vector, pose_vector) + if args.perf: + torch.cuda.synchronize() + print("model", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = output_image.cpu() + if args.perf: + print("cpu()", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = postprocessing_image(postprocessed_image) + if args.perf: + print("postprocess", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + + self.output_queue.put_nowait(postprocessed_image) + + + + + @torch.no_grad() def main(): - model = None - if not args.skip_model: - model = TalkingAnimeLight().to(device) - model = model.eval() - model = model - print("Pretrained Model Loaded") img = Image.open(f"character/{args.character}.png") wRatio = img.size[0] / 256 img = img.resize((256, int(img.size[1] / wRatio))) @@ -182,7 +236,7 @@ def main(): cam_scale = 1 if args.anime4k: cam_scale = 2 - cam = pyvirtualcam.Camera(width=args.output_w * cam_scale, height=args.output_h * cam_scale, fps=30, + cam = pyvirtualcam.Camera(width=args.output_w * cam_scale, height=args.output_h * cam_scale, fps=60, backend=args.output_webcam, fmt= {'unitycapture': pyvirtualcam.PixelFormat.RGBA, 'obs': pyvirtualcam.PixelFormat.RGB}[ @@ -208,30 +262,23 @@ def main(): a.set_arguments(parameters) print("Anime4K Loaded") - mouth_eye_vector = torch.empty(1, 27) - pose_vector = torch.empty(1, 3) - mouth_eye_vector_c = [0.0]*27 - pose_vector_c = [0.0]*3 - - # input_image = input_image.half() - # mouth_eye_vector = mouth_eye_vector.half() - # pose_vector = pose_vector.half() - - input_image = input_image.to(device) - mouth_eye_vector = mouth_eye_vector.to(device) - pose_vector = pose_vector.to(device) position_vector = [0, 0, 0, 1] pose_queue = [] blender_data = create_default_blender_data() tic1 = 0 - vector_hash=None - prev_hash=None - changed_count=0 - missed_count=0 - tot_count=0 - model_cache=OrderedDict() + model_output=None + model_process=ModelClientProcess(input_image) + model_process.daemon = True + model_process.start() + + vector_hash = None + prev_hash = None + changed_count = 0 + missed_count = 0 + tot_count = 0 + model_cache = OrderedDict() print("Ready. Close this console to exit.") @@ -244,8 +291,8 @@ def main(): print('===') tic = time.perf_counter() if args.debug_input: - mouth_eye_vector_c = [0.0]*27 - pose_vector_c = [0.0]*3 + mouth_eye_vector_c = [0.0] * 27 + pose_vector_c = [0.0] * 3 mouth_eye_vector_c[2] = math.sin(time.perf_counter() * 3) mouth_eye_vector_c[3] = math.sin(time.perf_counter() * 3) @@ -292,8 +339,8 @@ def main(): # - ifacialmocap_pose[EYE_LOOK_DOWN_RIGHT] # + ifacialmocap_pose[EYE_LOOK_DOWN_LEFT]) / 2.0 / 0.75 - mouth_eye_vector_c = [0.0]*27 - pose_vector_c = [0.0]*3 + mouth_eye_vector_c = [0.0] * 27 + pose_vector_c = [0.0] * 3 for i in range(12, 39): mouth_eye_vector_c[i - 12] = ifacialmocap_pose_converted[i] for i in range(39, 42): @@ -355,42 +402,33 @@ def main(): print("input", time.perf_counter() - tic) tic = time.perf_counter() - hash_arr=mouth_eye_vector_c - hash_arr.extend(pose_vector_c) - vector_hash=hash(tuple(hash_arr)) - tot_count+=1 - if vector_hash==prev_hash: continue + model_input_arr = mouth_eye_vector_c + model_input_arr.extend(pose_vector_c) + vector_hash = hash(tuple(model_input_arr)) + tot_count += 1 + if vector_hash == prev_hash: continue # print("hash", vector_hash) - if vector_hash!=prev_hash: changed_count+=1 - prev_hash=vector_hash + if vector_hash != prev_hash: changed_count += 1 + prev_hash = vector_hash if model_cache.get(vector_hash) is None: - model_cache[vector_hash]=True - missed_count+=1 + model_cache[vector_hash] = True + missed_count += 1 # # print('changed ratio',changed_count/tot_count*100) # print('missed ratio',missed_count/tot_count*100) - for i in range(27): - mouth_eye_vector[0,i]=mouth_eye_vector_c[i] - for i in range(3): - pose_vector[0,i]=pose_vector_c[i] - torch.cuda.synchronize() - if model is None: - output_image=input_image - else: - output_image = model(input_image, mouth_eye_vector, pose_vector) - if args.perf: - torch.cuda.synchronize() - print("model", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() - postprocessed_image = output_image.cpu() - if args.perf: - print("cpu()", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() - postprocessed_image = postprocessing_image(postprocessed_image) - if args.perf: - print("postprocess", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() + model_process.input_queue.put_nowait(model_input_arr) + + try: + new_model_output = model_output + while not model_process.output_queue.empty(): + new_model_output = model_process.output_queue.get_nowait() + model_output = new_model_output + except queue.Empty: + pass + if model_output is None: continue + postprocessed_image=model_output + if extra_image is not None: postprocessed_image = cv2.vconcat([postprocessed_image, extra_image]) From bc8f44f290ea265c83be2cc37b255dfce003f3a7 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sat, 14 May 2022 23:52:07 +0800 Subject: [PATCH 04/21] --alpha_split --- args.py | 1 + main.py | 31 +++++++++++++++++++------- obs_shader/merge alpha2.hlsl | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 obs_shader/merge alpha2.hlsl diff --git a/args.py b/args.py index b256ea1..81e073d 100644 --- a/args.py +++ b/args.py @@ -13,6 +13,7 @@ parser.add_argument('--perf', action='store_true') parser.add_argument('--skip_model', action='store_true') parser.add_argument('--ifm', type=str) parser.add_argument('--anime4k', action='store_true') +parser.add_argument('--alpha_split', action='store_true') args = parser.parse_args() args.output_w = int(args.output_size.split('x')[0]) args.output_h = int(args.output_size.split('x')[1]) diff --git a/main.py b/main.py index 6e10749..46e76e1 100644 --- a/main.py +++ b/main.py @@ -166,6 +166,8 @@ class ModelClientProcess(Process): continue if input is None: continue + if args.perf: + tic = time.perf_counter() for i in range(27): mouth_eye_vector[0, i] = input[i] for i in range(3): @@ -234,9 +236,12 @@ def main(): if args.output_webcam: cam_scale = 1 + cam_width_scale=1 if args.anime4k: cam_scale = 2 - cam = pyvirtualcam.Camera(width=args.output_w * cam_scale, height=args.output_h * cam_scale, fps=60, + if args.alpha_split: + cam_width_scale=2 + cam = pyvirtualcam.Camera(width=args.output_w * cam_scale * cam_width_scale, height=args.output_h * cam_scale, fps=60, backend=args.output_webcam, fmt= {'unitycapture': pyvirtualcam.PixelFormat.RGBA, 'obs': pyvirtualcam.PixelFormat.RGB}[ @@ -288,7 +293,6 @@ def main(): # results = facemesh.process(input_frame) if args.perf: - print('===') tic = time.perf_counter() if args.debug_input: mouth_eye_vector_c = [0.0] * 27 @@ -316,7 +320,7 @@ def main(): new_blender_data = client_process.queue.get_nowait() blender_data = new_blender_data except queue.Empty: - continue + pass ifacialmocap_pose_converted = ifm_converter.convert(blender_data) @@ -398,15 +402,14 @@ def main(): pose_vector_c[1] = y_angle * 2.0 # temp weight pose_vector_c[2] = (z_angle + 1.5) * 2 # temp weight - if args.perf: - print("input", time.perf_counter() - tic) - tic = time.perf_counter() model_input_arr = mouth_eye_vector_c model_input_arr.extend(pose_vector_c) vector_hash = hash(tuple(model_input_arr)) tot_count += 1 - if vector_hash == prev_hash: continue + if vector_hash == prev_hash: + continue + # print("hash", vector_hash) if vector_hash != prev_hash: changed_count += 1 prev_hash = vector_hash @@ -426,9 +429,16 @@ def main(): model_output = new_model_output except queue.Empty: pass - if model_output is None: continue + if model_output is None: + time.sleep(1) + continue postprocessed_image=model_output + if args.perf: + print('===') + print("input", time.perf_counter() - tic) + tic = time.perf_counter() + if extra_image is not None: postprocessed_image = cv2.vconcat([postprocessed_image, extra_image]) @@ -470,6 +480,11 @@ def main(): if args.perf: print("anime4k", (time.perf_counter() - tic) * 1000) tic = time.perf_counter() + if args.alpha_split: + alpha_image=cv2.merge([postprocessed_image[:, :, 3],postprocessed_image[:, :, 3],postprocessed_image[:, :, 3]]) + alpha_image=cv2.cvtColor(alpha_image, cv2.COLOR_RGB2RGBA) + postprocessed_image=cv2.hconcat([postprocessed_image,alpha_image]) + if args.debug: output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) # resized_frame = cv2.resize(output_frame, (np.min(debug_image.shape[:2]), np.min(debug_image.shape[:2]))) diff --git a/obs_shader/merge alpha2.hlsl b/obs_shader/merge alpha2.hlsl new file mode 100644 index 0000000..151a35f --- /dev/null +++ b/obs_shader/merge alpha2.hlsl @@ -0,0 +1,43 @@ +uniform float4x4 ViewProj< + bool automatic = true; + string name = "View Projection Matrix"; +>; +uniform texture2d InputA< + bool automatic = true; +>; + +uniform int mode; + +sampler_state textureSampler { + Filter = Linear; + AddressU = Clamp; + AddressV = Clamp; +}; + +struct VertData { + float4 pos : POSITION; + float2 uv : TEXCOORD0; +}; + +VertData VSDefault(VertData vtx) +{ + vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); + return vtx; +} + +float4 PSAlphaFilter(VertData vtx) : TARGET +{ + float2 uv = vtx.uv; + float3 pixel = InputA.Sample(textureSampler, float2(vtx.uv.x, vtx.uv.y)).rgb; + float alpha = InputA.Sample(textureSampler, float2(vtx.uv.x + 0.5, vtx.uv.y)).g; + return float4(clamp(pixel.rgb / alpha, 0.0, 1.0), alpha); +} + +technique Draw +{ + pass + { + vertex_shader = VSDefault(vtx); + pixel_shader = PSAlphaFilter(vtx); + } +} \ No newline at end of file From b845c741a7f4f17523ab814609768cb4d2f39f20 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 15 May 2022 02:18:53 +0800 Subject: [PATCH 05/21] remove mouth_uuu --- main.py | 12 ++++++++++-- tha2/poser/modes/mode_20_wx.py | 6 ++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/main.py b/main.py index 46e76e1..d61592e 100644 --- a/main.py +++ b/main.py @@ -407,8 +407,9 @@ def main(): model_input_arr.extend(pose_vector_c) vector_hash = hash(tuple(model_input_arr)) tot_count += 1 - if vector_hash == prev_hash: - continue + should_output=False + if vector_hash != prev_hash: + should_output=True # print("hash", vector_hash) if vector_hash != prev_hash: changed_count += 1 @@ -422,9 +423,11 @@ def main(): model_process.input_queue.put_nowait(model_input_arr) + has_model_output=0 try: new_model_output = model_output while not model_process.output_queue.empty(): + has_model_output+=1 new_model_output = model_process.output_queue.get_nowait() model_output = new_model_output except queue.Empty: @@ -432,6 +435,11 @@ def main(): if model_output is None: time.sleep(1) continue + # print(has_model_output) + # should_output=should_output or has_model_output + # if not should_output: + # continue + postprocessed_image=model_output if args.perf: diff --git a/tha2/poser/modes/mode_20_wx.py b/tha2/poser/modes/mode_20_wx.py index 9d8955c..f78d640 100644 --- a/tha2/poser/modes/mode_20_wx.py +++ b/tha2/poser/modes/mode_20_wx.py @@ -268,11 +268,13 @@ class IFacialMocapPoseConverter20(IFacialMocapPoseConverter): # [decomp.item(0), decomp.item(1), decomp.item(2), decomp.item(3)]) pose[self.mouth_aaa_index] = restricted_decomp[0] pose[self.mouth_iii_index] = restricted_decomp[1] - mouth_funnel_denom = self.args.mouth_funnel_max_value - self.args.mouth_funnel_min_value - ooo_alpha = clamp((mouth_funnel - self.args.mouth_funnel_min_value) / mouth_funnel_denom, 0.0, 1.0) + # mouth_funnel_denom = self.args.mouth_funnel_max_value - self.args.mouth_funnel_min_value + # ooo_alpha = clamp((mouth_funnel - self.args.mouth_funnel_min_value) / mouth_funnel_denom, 0.0, 1.0) + ooo_alpha=1 uo_value = clamp(restricted_decomp[2] + restricted_decomp[3], 0.0, 1.0) pose[self.mouth_uuu_index] = uo_value * (1.0 - ooo_alpha) pose[self.mouth_ooo_index] = uo_value * ooo_alpha + print(pose[self.mouth_aaa_index:self.mouth_ooo_index+1]) # pose[28] = restricted_decomp[2] # pose[30] = restricted_decomp[3] From 993ffe27c0c743b767805bfa046c9011fd8e3a83 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 15 May 2022 04:43:59 +0800 Subject: [PATCH 06/21] cached --- main.py | 83 +++++++++++++++------------------- tha2/poser/modes/mode_20_wx.py | 2 +- 2 files changed, 38 insertions(+), 47 deletions(-) diff --git a/main.py b/main.py index d61592e..e3b8d93 100644 --- a/main.py +++ b/main.py @@ -20,7 +20,6 @@ import math from collections import OrderedDict from multiprocessing import Value, Process, Queue -import pyanime4k from pyanime4k import ac from tha2.mocap.ifacialmocap_constants import * @@ -157,6 +156,10 @@ class ModelClientProcess(Process): mouth_eye_vector = mouth_eye_vector.to(device) pose_vector = pose_vector.to(device) + model_cache = OrderedDict() + tot = 0 + hit = 0 + while True: input = None try: @@ -165,31 +168,41 @@ class ModelClientProcess(Process): except queue.Empty: continue if input is None: continue - - if args.perf: - tic = time.perf_counter() - for i in range(27): - mouth_eye_vector[0, i] = input[i] - for i in range(3): - pose_vector[0, i] = input[i+27] - if model is None: - output_image = input_image + input=[round(x*100)/100 for x in input] + input_hash=hash(tuple(input)) + cached=model_cache.get(input_hash) + tot+=1 + if not cached is None: + self.output_queue.put_nowait(cached) + model_cache.move_to_end(input_hash) + hit+=1 + print('cached',hit/tot*100) else: - output_image = model(input_image, mouth_eye_vector, pose_vector) - if args.perf: - torch.cuda.synchronize() - print("model", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() - postprocessed_image = output_image.cpu() - if args.perf: - print("cpu()", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() - postprocessed_image = postprocessing_image(postprocessed_image) - if args.perf: - print("postprocess", (time.perf_counter() - tic) * 1000) - tic = time.perf_counter() + if args.perf: + tic = time.perf_counter() + for i in range(27): + mouth_eye_vector[0, i] = input[i] + for i in range(3): + pose_vector[0, i] = input[i+27] + if model is None: + output_image = input_image + else: + output_image = model(input_image, mouth_eye_vector, pose_vector) + if args.perf: + torch.cuda.synchronize() + print("model", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = output_image.cpu() + if args.perf: + print("cpu()", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() + postprocessed_image = postprocessing_image(postprocessed_image) + if args.perf: + print("postprocess", (time.perf_counter() - tic) * 1000) + tic = time.perf_counter() - self.output_queue.put_nowait(postprocessed_image) + model_cache[input_hash]=postprocessed_image + self.output_queue.put_nowait(postprocessed_image) @@ -278,13 +291,6 @@ def main(): model_process.daemon = True model_process.start() - vector_hash = None - prev_hash = None - changed_count = 0 - missed_count = 0 - tot_count = 0 - model_cache = OrderedDict() - print("Ready. Close this console to exit.") while True: @@ -405,21 +411,6 @@ def main(): model_input_arr = mouth_eye_vector_c model_input_arr.extend(pose_vector_c) - vector_hash = hash(tuple(model_input_arr)) - tot_count += 1 - should_output=False - if vector_hash != prev_hash: - should_output=True - - # print("hash", vector_hash) - if vector_hash != prev_hash: changed_count += 1 - prev_hash = vector_hash - if model_cache.get(vector_hash) is None: - model_cache[vector_hash] = True - missed_count += 1 - # - # print('changed ratio',changed_count/tot_count*100) - # print('missed ratio',missed_count/tot_count*100) model_process.input_queue.put_nowait(model_input_arr) diff --git a/tha2/poser/modes/mode_20_wx.py b/tha2/poser/modes/mode_20_wx.py index f78d640..b898f3b 100644 --- a/tha2/poser/modes/mode_20_wx.py +++ b/tha2/poser/modes/mode_20_wx.py @@ -274,7 +274,7 @@ class IFacialMocapPoseConverter20(IFacialMocapPoseConverter): uo_value = clamp(restricted_decomp[2] + restricted_decomp[3], 0.0, 1.0) pose[self.mouth_uuu_index] = uo_value * (1.0 - ooo_alpha) pose[self.mouth_ooo_index] = uo_value * ooo_alpha - print(pose[self.mouth_aaa_index:self.mouth_ooo_index+1]) + # print(pose[self.mouth_aaa_index:self.mouth_ooo_index+1]) # pose[28] = restricted_decomp[2] # pose[30] = restricted_decomp[3] From f5568c4c4e531eb28e18e00fddc4b76b66c5608c Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 15 May 2022 17:26:01 +0800 Subject: [PATCH 07/21] cached --- args.py | 15 +++++++++++++++ main.py | 9 +++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/args.py b/args.py index 81e073d..dcfd223 100644 --- a/args.py +++ b/args.py @@ -1,4 +1,14 @@ import argparse +import re + +def convert_to_byte(size): + result = re.search('(\d+\.?\d*)(b|kb|mb|gb|tb)', size.lower()) + if (result and result.groups()): + unit = result.groups()[1] + amount = float(result.groups()[0]) + index = ['b', 'kb', 'mb', 'gb', 'tb'].index(unit) + return amount * pow(1024, index) + raise ValueError("Invalid size provided, value is " + size) parser = argparse.ArgumentParser() parser.add_argument('--debug', action='store_true') @@ -14,7 +24,12 @@ parser.add_argument('--skip_model', action='store_true') parser.add_argument('--ifm', type=str) parser.add_argument('--anime4k', action='store_true') parser.add_argument('--alpha_split', action='store_true') +parser.add_argument('--cache', type=str, default='100mb') args = parser.parse_args() args.output_w = int(args.output_size.split('x')[0]) args.output_h = int(args.output_size.split('x')[1]) +if args.cache is not None: + args.max_cache_len=int(convert_to_byte(args.cache)/262144) +else: + args.max_cache_len=0 if args.output_webcam is None and args.output_dir is None: args.debug = True \ No newline at end of file diff --git a/main.py b/main.py index e3b8d93..ffb278d 100644 --- a/main.py +++ b/main.py @@ -17,6 +17,7 @@ import queue import socket import time import math +import re from collections import OrderedDict from multiprocessing import Value, Process, Queue @@ -201,11 +202,11 @@ class ModelClientProcess(Process): print("postprocess", (time.perf_counter() - tic) * 1000) tic = time.perf_counter() - model_cache[input_hash]=postprocessed_image self.output_queue.put_nowait(postprocessed_image) - - - + if args.max_cache_len>0: + model_cache[input_hash]=postprocessed_image + if len(model_cache)>args.max_cache_len: + model_cache.popitem(0) @torch.no_grad() From 94e27a90eab77ad269e93aab7bb29f939155ab7f Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 15 May 2022 17:27:03 +0800 Subject: [PATCH 08/21] cached --- main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index ffb278d..abf64d1 100644 --- a/main.py +++ b/main.py @@ -177,7 +177,8 @@ class ModelClientProcess(Process): self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit+=1 - print('cached',hit/tot*100) + if args.perf: + print('cached',str(hit/tot*100)+'%') else: if args.perf: tic = time.perf_counter() From d11cb75350306dc0b8ac4a1a63961353d7320b33 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sat, 21 May 2022 21:41:53 +0800 Subject: [PATCH 09/21] cached --- LICENSE | 2 +- main.py | 9 +++++---- tha2/poser/modes/mode_20_wx.py | 14 +++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index 1d8c44b..2a663dd 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021 Gunwoo Han +Copyright (c) 2021 Gunwoo Han, yuyuyzl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/main.py b/main.py index abf64d1..032810a 100644 --- a/main.py +++ b/main.py @@ -54,6 +54,8 @@ def create_default_blender_data(): return data +ifm_converter = tha2.poser.modes.mode_20_wx.IFacialMocapPoseConverter20() + class IFMClientProcess(Process): def __init__(self): super().__init__() @@ -170,6 +172,8 @@ class ModelClientProcess(Process): continue if input is None: continue input=[round(x*100)/100 for x in input] + input[ifm_converter.iris_rotation_y_index - 12]=round(input[ifm_converter.iris_rotation_y_index - 12]*100)/100 + input[ifm_converter.iris_rotation_x_index - 12]=round(input[ifm_converter.iris_rotation_x_index - 12]*100)/100 input_hash=hash(tuple(input)) cached=model_cache.get(input_hash) tot+=1 @@ -177,7 +181,7 @@ class ModelClientProcess(Process): self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit+=1 - if args.perf: + if (args.perf)or hit%100==0: print('cached',str(hit/tot*100)+'%') else: if args.perf: @@ -221,8 +225,6 @@ def main(): extra_image = np.array(img.crop((0, 256, img.size[0], img.size[1]))) print("Character Image Loaded:", args.character) - - ifm_converter = None cap = None if not args.debug_input: @@ -231,7 +233,6 @@ def main(): client_process = IFMClientProcess() client_process.daemon = True client_process.start() - ifm_converter = tha2.poser.modes.mode_20_wx.create_ifacialmocap_pose_converter() print("IFM Service Running:", args.ifm) else: diff --git a/tha2/poser/modes/mode_20_wx.py b/tha2/poser/modes/mode_20_wx.py index b898f3b..cbbfdf2 100644 --- a/tha2/poser/modes/mode_20_wx.py +++ b/tha2/poser/modes/mode_20_wx.py @@ -86,7 +86,7 @@ class IFacialMocapPoseConverter20(IFacialMocapPoseConverter): self.eyebrow_serious_left_index = pose_parameters.get_parameter_index("eyebrow_serious_left") self.eyebrow_serious_right_index = pose_parameters.get_parameter_index("eyebrow_serious_right") - self.eye_surprised_left_index = pose_parameters.get_parameter_index("eye_surprised_left") + self.eye_surprised_left_index = pose_parameters.get_parameter_index("eye_surprised_left") # 0 self.eye_surprised_right_index = pose_parameters.get_parameter_index("eye_surprised_right") self.eye_wink_left_index = pose_parameters.get_parameter_index("eye_wink_left") self.eye_wink_right_index = pose_parameters.get_parameter_index("eye_wink_right") @@ -95,13 +95,13 @@ class IFacialMocapPoseConverter20(IFacialMocapPoseConverter): self.eye_relaxed_left_index = pose_parameters.get_parameter_index("eye_relaxed_left") self.eye_relaxed_right_index = pose_parameters.get_parameter_index("eye_relaxed_right") self.eye_raised_lower_eyelid_left_index = pose_parameters.get_parameter_index("eye_raised_lower_eyelid_left") - self.eye_raised_lower_eyelid_right_index = pose_parameters.get_parameter_index("eye_raised_lower_eyelid_right") + self.eye_raised_lower_eyelid_right_index = pose_parameters.get_parameter_index("eye_raised_lower_eyelid_right") # 9 - self.iris_small_left_index = pose_parameters.get_parameter_index("iris_small_left") + self.iris_small_left_index = pose_parameters.get_parameter_index("iris_small_left")#10 self.iris_small_right_index = pose_parameters.get_parameter_index("iris_small_right") self.iris_rotation_x_index = pose_parameters.get_parameter_index("iris_rotation_x") - self.iris_rotation_y_index = pose_parameters.get_parameter_index("iris_rotation_y") + self.iris_rotation_y_index = pose_parameters.get_parameter_index("iris_rotation_y")#13 self.head_x_index = pose_parameters.get_parameter_index("head_x") self.head_y_index = pose_parameters.get_parameter_index("head_y") @@ -268,9 +268,9 @@ class IFacialMocapPoseConverter20(IFacialMocapPoseConverter): # [decomp.item(0), decomp.item(1), decomp.item(2), decomp.item(3)]) pose[self.mouth_aaa_index] = restricted_decomp[0] pose[self.mouth_iii_index] = restricted_decomp[1] - # mouth_funnel_denom = self.args.mouth_funnel_max_value - self.args.mouth_funnel_min_value - # ooo_alpha = clamp((mouth_funnel - self.args.mouth_funnel_min_value) / mouth_funnel_denom, 0.0, 1.0) - ooo_alpha=1 + mouth_funnel_denom = self.args.mouth_funnel_max_value - self.args.mouth_funnel_min_value + ooo_alpha = clamp((mouth_funnel - self.args.mouth_funnel_min_value) / mouth_funnel_denom, 0.0, 1.0) + # ooo_alpha = 1 uo_value = clamp(restricted_decomp[2] + restricted_decomp[3], 0.0, 1.0) pose[self.mouth_uuu_index] = uo_value * (1.0 - ooo_alpha) pose[self.mouth_ooo_index] = uo_value * ooo_alpha From f47e65ab9b2d7fe0eb69c5308f494bfb25f4514c Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 01:37:50 +0800 Subject: [PATCH 10/21] staged simplify --- args.py | 1 + main.py | 122 +++++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/args.py b/args.py index dcfd223..ea13ae3 100644 --- a/args.py +++ b/args.py @@ -25,6 +25,7 @@ parser.add_argument('--ifm', type=str) parser.add_argument('--anime4k', action='store_true') parser.add_argument('--alpha_split', action='store_true') parser.add_argument('--cache', type=str, default='100mb') +parser.add_argument('--simplify', type=int, default=1) args = parser.parse_args() args.output_w = int(args.output_size.split('x')[0]) args.output_h = int(args.output_size.split('x')[1]) diff --git a/main.py b/main.py index 032810a..ae54328 100644 --- a/main.py +++ b/main.py @@ -56,6 +56,7 @@ def create_default_blender_data(): ifm_converter = tha2.poser.modes.mode_20_wx.IFacialMocapPoseConverter20() + class IFMClientProcess(Process): def __init__(self): super().__init__() @@ -138,11 +139,11 @@ class ModelClientProcess(Process): def __init__(self, input_image): super().__init__() self.should_terminate = Value('b', False) - self.updated=Value('b', False) + self.updated = Value('b', False) self.data = None self.input_image = input_image - self.output_queue=Queue() - self.input_queue=Queue() + self.output_queue = Queue() + self.input_queue = Queue() def run(self): model = None @@ -164,32 +165,88 @@ class ModelClientProcess(Process): hit = 0 while True: - input = None + model_input = None try: while not self.input_queue.empty(): - input = self.input_queue.get_nowait() + model_input = self.input_queue.get_nowait() except queue.Empty: continue - if input is None: continue - input=[round(x*100)/100 for x in input] - input[ifm_converter.iris_rotation_y_index - 12]=round(input[ifm_converter.iris_rotation_y_index - 12]*100)/100 - input[ifm_converter.iris_rotation_x_index - 12]=round(input[ifm_converter.iris_rotation_x_index - 12]*100)/100 - input_hash=hash(tuple(input)) - cached=model_cache.get(input_hash) - tot+=1 + if model_input is None: continue + simplify_arr = [1000] * ifm_converter.pose_size + if args.simplify >= 1: + simplify_arr = [200] * ifm_converter.pose_size + simplify_arr[ifm_converter.eye_wink_left_index] = 50 + simplify_arr[ifm_converter.eye_wink_right_index] = 50 + simplify_arr[ifm_converter.eye_happy_wink_left_index] = 50 + simplify_arr[ifm_converter.eye_happy_wink_right_index] = 50 + simplify_arr[ifm_converter.eye_surprised_left_index] = 30 + simplify_arr[ifm_converter.eye_surprised_right_index] = 30 + simplify_arr[ifm_converter.iris_rotation_x_index] = 25 + simplify_arr[ifm_converter.iris_rotation_y_index] = 25 + simplify_arr[ifm_converter.eye_raised_lower_eyelid_left_index] = 10 + simplify_arr[ifm_converter.eye_raised_lower_eyelid_right_index] = 10 + simplify_arr[ifm_converter.mouth_lowered_corner_left_index] = 5 + simplify_arr[ifm_converter.mouth_lowered_corner_right_index] = 5 + simplify_arr[ifm_converter.mouth_raised_corner_left_index] = 5 + simplify_arr[ifm_converter.mouth_raised_corner_right_index] = 5 + if args.simplify >= 2: + simplify_arr[ifm_converter.head_x_index]=100 + simplify_arr[ifm_converter.head_y_index]=100 + simplify_arr[ifm_converter.eye_surprised_left_index] = 10 + simplify_arr[ifm_converter.eye_surprised_right_index] = 10 + model_input[ifm_converter.eye_wink_left_index - 12] += model_input[ + ifm_converter.eye_happy_wink_left_index - 12] + model_input[ifm_converter.eye_happy_wink_left_index - 12] = model_input[ + ifm_converter.eye_wink_left_index - 12] / 2 + model_input[ifm_converter.eye_wink_left_index - 12] = model_input[ + ifm_converter.eye_wink_left_index - 12] / 2 + model_input[ifm_converter.eye_wink_right_index - 12] += model_input[ + ifm_converter.eye_happy_wink_right_index - 12] + model_input[ifm_converter.eye_happy_wink_right_index - 12] = model_input[ + ifm_converter.eye_wink_right_index - 12] / 2 + model_input[ifm_converter.eye_wink_right_index - 12] = model_input[ + ifm_converter.eye_wink_right_index - 12] / 2 + + uosum = model_input[ifm_converter.mouth_uuu_index - 12] + \ + model_input[ifm_converter.mouth_ooo_index - 12] + model_input[ifm_converter.mouth_ooo_index - 12] = uosum + model_input[ifm_converter.mouth_uuu_index - 12] = 0 + is_open = (model_input[ifm_converter.mouth_aaa_index - 12] + model_input[ + ifm_converter.mouth_iii_index - 12] + uosum) > 0 + model_input[ifm_converter.mouth_lowered_corner_left_index - 12] = 0 + model_input[ifm_converter.mouth_lowered_corner_right_index - 12] = 0 + model_input[ifm_converter.mouth_raised_corner_left_index - 12] = 0.5 if is_open else 0 + model_input[ifm_converter.mouth_raised_corner_right_index - 12] = 0.5 if is_open else 0 + simplify_arr[ifm_converter.mouth_lowered_corner_left_index] = 0 + simplify_arr[ifm_converter.mouth_lowered_corner_right_index] = 0 + simplify_arr[ifm_converter.mouth_raised_corner_left_index] = 0 + simplify_arr[ifm_converter.mouth_raised_corner_right_index] = 0 + if args.simplify >= 3: + simplify_arr[ifm_converter.iris_rotation_x_index] = 20 + simplify_arr[ifm_converter.iris_rotation_y_index] = 20 + simplify_arr[ifm_converter.eye_wink_left_index] = 25 + simplify_arr[ifm_converter.eye_wink_right_index] = 25 + simplify_arr[ifm_converter.eye_happy_wink_left_index] = 25 + simplify_arr[ifm_converter.eye_happy_wink_right_index] = 25 + for i in range(12, len(simplify_arr)): + if simplify_arr[i] > 0: + model_input[i - 12] = round(model_input[i - 12] * simplify_arr[i]) / simplify_arr[i] + input_hash = hash(tuple(model_input)) + cached = model_cache.get(input_hash) + tot += 1 if not cached is None: self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) - hit+=1 - if (args.perf)or hit%100==0: - print('cached',str(hit/tot*100)+'%') + hit += 1 + if (args.perf) or hit % 10 == 0: + print('cached', str(hit / tot * 100) + '%') else: if args.perf: tic = time.perf_counter() for i in range(27): - mouth_eye_vector[0, i] = input[i] + mouth_eye_vector[0, i] = model_input[i] for i in range(3): - pose_vector[0, i] = input[i+27] + pose_vector[0, i] = model_input[i + 27] if model is None: output_image = input_image else: @@ -208,9 +265,9 @@ class ModelClientProcess(Process): tic = time.perf_counter() self.output_queue.put_nowait(postprocessed_image) - if args.max_cache_len>0: - model_cache[input_hash]=postprocessed_image - if len(model_cache)>args.max_cache_len: + if args.max_cache_len > 0: + model_cache[input_hash] = postprocessed_image + if len(model_cache) > args.max_cache_len: model_cache.popitem(0) @@ -252,12 +309,13 @@ def main(): if args.output_webcam: cam_scale = 1 - cam_width_scale=1 + cam_width_scale = 1 if args.anime4k: cam_scale = 2 if args.alpha_split: - cam_width_scale=2 - cam = pyvirtualcam.Camera(width=args.output_w * cam_scale * cam_width_scale, height=args.output_h * cam_scale, fps=60, + cam_width_scale = 2 + cam = pyvirtualcam.Camera(width=args.output_w * cam_scale * cam_width_scale, height=args.output_h * cam_scale, + fps=60, backend=args.output_webcam, fmt= {'unitycapture': pyvirtualcam.PixelFormat.RGBA, 'obs': pyvirtualcam.PixelFormat.RGB}[ @@ -289,8 +347,8 @@ def main(): blender_data = create_default_blender_data() tic1 = 0 - model_output=None - model_process=ModelClientProcess(input_image) + model_output = None + model_process = ModelClientProcess(input_image) model_process.daemon = True model_process.start() @@ -411,17 +469,16 @@ def main(): pose_vector_c[1] = y_angle * 2.0 # temp weight pose_vector_c[2] = (z_angle + 1.5) * 2 # temp weight - model_input_arr = mouth_eye_vector_c model_input_arr.extend(pose_vector_c) model_process.input_queue.put_nowait(model_input_arr) - has_model_output=0 + has_model_output = 0 try: new_model_output = model_output while not model_process.output_queue.empty(): - has_model_output+=1 + has_model_output += 1 new_model_output = model_process.output_queue.get_nowait() model_output = new_model_output except queue.Empty: @@ -434,7 +491,7 @@ def main(): # if not should_output: # continue - postprocessed_image=model_output + postprocessed_image = model_output if args.perf: print('===') @@ -483,9 +540,10 @@ def main(): print("anime4k", (time.perf_counter() - tic) * 1000) tic = time.perf_counter() if args.alpha_split: - alpha_image=cv2.merge([postprocessed_image[:, :, 3],postprocessed_image[:, :, 3],postprocessed_image[:, :, 3]]) - alpha_image=cv2.cvtColor(alpha_image, cv2.COLOR_RGB2RGBA) - postprocessed_image=cv2.hconcat([postprocessed_image,alpha_image]) + alpha_image = cv2.merge( + [postprocessed_image[:, :, 3], postprocessed_image[:, :, 3], postprocessed_image[:, :, 3]]) + alpha_image = cv2.cvtColor(alpha_image, cv2.COLOR_RGB2RGBA) + postprocessed_image = cv2.hconcat([postprocessed_image, alpha_image]) if args.debug: output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) From c3d22d4d090cedccce9d1c0dec369d6ec0e26e33 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 02:12:08 +0800 Subject: [PATCH 11/21] staged simplify --- main.py | 48 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index ae54328..49819cc 100644 --- a/main.py +++ b/main.py @@ -189,9 +189,10 @@ class ModelClientProcess(Process): simplify_arr[ifm_converter.mouth_lowered_corner_right_index] = 5 simplify_arr[ifm_converter.mouth_raised_corner_left_index] = 5 simplify_arr[ifm_converter.mouth_raised_corner_right_index] = 5 + if args.simplify >= 2: - simplify_arr[ifm_converter.head_x_index]=100 - simplify_arr[ifm_converter.head_y_index]=100 + simplify_arr[ifm_converter.head_x_index] = 100 + simplify_arr[ifm_converter.head_y_index] = 100 simplify_arr[ifm_converter.eye_surprised_left_index] = 10 simplify_arr[ifm_converter.eye_surprised_right_index] = 10 model_input[ifm_converter.eye_wink_left_index - 12] += model_input[ @@ -224,10 +225,45 @@ class ModelClientProcess(Process): if args.simplify >= 3: simplify_arr[ifm_converter.iris_rotation_x_index] = 20 simplify_arr[ifm_converter.iris_rotation_y_index] = 20 - simplify_arr[ifm_converter.eye_wink_left_index] = 25 - simplify_arr[ifm_converter.eye_wink_right_index] = 25 - simplify_arr[ifm_converter.eye_happy_wink_left_index] = 25 - simplify_arr[ifm_converter.eye_happy_wink_right_index] = 25 + simplify_arr[ifm_converter.eye_wink_left_index] = 32 + simplify_arr[ifm_converter.eye_wink_right_index] = 32 + simplify_arr[ifm_converter.eye_happy_wink_left_index] = 32 + simplify_arr[ifm_converter.eye_happy_wink_right_index] = 32 + if args.simplify >= 4: + simplify_arr[ifm_converter.head_x_index] = 50 + simplify_arr[ifm_converter.head_y_index] = 50 + simplify_arr[ifm_converter.neck_z_index] = 100 + model_input[ifm_converter.eye_raised_lower_eyelid_left_index - 12] = 0 + model_input[ifm_converter.eye_raised_lower_eyelid_right_index - 12] = 0 + simplify_arr[ifm_converter.iris_rotation_x_index] = 10 + simplify_arr[ifm_converter.iris_rotation_y_index] = 10 + simplify_arr[ifm_converter.eye_wink_left_index] = 24 + simplify_arr[ifm_converter.eye_wink_right_index] = 24 + simplify_arr[ifm_converter.eye_happy_wink_left_index] = 24 + simplify_arr[ifm_converter.eye_happy_wink_right_index] = 24 + simplify_arr[ifm_converter.eye_surprised_left_index] = 8 + simplify_arr[ifm_converter.eye_surprised_right_index] = 8 + model_input[ifm_converter.eye_wink_left_index - 12] += model_input[ + ifm_converter.eye_wink_right_index - 12] + model_input[ifm_converter.eye_wink_right_index - 12] = model_input[ + ifm_converter.eye_wink_left_index - 12] / 2 + model_input[ifm_converter.eye_wink_left_index - 12] = model_input[ + ifm_converter.eye_wink_left_index - 12] / 2 + + model_input[ifm_converter.eye_surprised_left_index - 12] += model_input[ + ifm_converter.eye_surprised_right_index - 12] + model_input[ifm_converter.eye_surprised_right_index - 12] = model_input[ + ifm_converter.eye_surprised_left_index - 12] / 2 + model_input[ifm_converter.eye_surprised_left_index - 12] = model_input[ + ifm_converter.eye_surprised_left_index - 12] / 2 + + model_input[ifm_converter.eye_happy_wink_left_index - 12] += model_input[ + ifm_converter.eye_happy_wink_right_index - 12] + model_input[ifm_converter.eye_happy_wink_right_index - 12] = model_input[ + ifm_converter.eye_happy_wink_left_index - 12] / 2 + model_input[ifm_converter.eye_happy_wink_left_index - 12] = model_input[ + ifm_converter.eye_happy_wink_left_index - 12] / 2 + for i in range(12, len(simplify_arr)): if simplify_arr[i] > 0: model_input[i - 12] = round(model_input[i - 12] * simplify_arr[i]) / simplify_arr[i] From c691f6c5cb1ff43c6a0441a88c41cb854c08c3bb Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 05:33:19 +0800 Subject: [PATCH 12/21] staged simplify --- main.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 49819cc..f20ea90 100644 --- a/main.py +++ b/main.py @@ -263,7 +263,17 @@ class ModelClientProcess(Process): ifm_converter.eye_happy_wink_left_index - 12] / 2 model_input[ifm_converter.eye_happy_wink_left_index - 12] = model_input[ ifm_converter.eye_happy_wink_left_index - 12] / 2 - + model_input[ifm_converter.mouth_aaa_index - 12] = min( + model_input[ifm_converter.mouth_aaa_index - 12]+ + model_input[ifm_converter.mouth_ooo_index - 12]/2+ + model_input[ifm_converter.mouth_iii_index - 12]/2+ + model_input[ifm_converter.mouth_uuu_index - 12]/2,1 + ) + model_input[ifm_converter.mouth_ooo_index - 12]=0 + model_input[ifm_converter.mouth_iii_index - 12]=0 + model_input[ifm_converter.mouth_uuu_index - 12]=0 + for i in range(4,args.simplify): + simplify_arr=[max(math.ceil(x*0.8),5)for x in simplify_arr] for i in range(12, len(simplify_arr)): if simplify_arr[i] > 0: model_input[i - 12] = round(model_input[i - 12] * simplify_arr[i]) / simplify_arr[i] From bab78653895932838ae9e2b243e51469ac8196ed Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 05:35:25 +0800 Subject: [PATCH 13/21] staged simplify --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index f20ea90..1700da4 100644 --- a/main.py +++ b/main.py @@ -284,7 +284,7 @@ class ModelClientProcess(Process): self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit += 1 - if (args.perf) or hit % 10 == 0: + if (args.perf) and hit % 20 == 0: print('cached', str(hit / tot * 100) + '%') else: if args.perf: From 0e6e0fab0826018f22ead750fa2fbfdcfaf3f566 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 06:17:37 +0800 Subject: [PATCH 14/21] doc --- README.md | 16 +++++++++++++ assets/alphasplit.png | Bin 0 -> 139513 bytes obs_shader/merge alpha2.hlsl | 43 ----------------------------------- 3 files changed, 16 insertions(+), 43 deletions(-) create mode 100644 assets/alphasplit.png delete mode 100644 obs_shader/merge alpha2.hlsl diff --git a/README.md b/README.md index 3ccf518..4ad5bb0 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Fork自 https://github.com/GunwooHan/EasyVtuber 并且省略了ifacialmocap pc端,通过UDP直连的方式使ios面捕刷新率达到30fps,解决了面捕刷新率的瓶颈 最后,将EasyVtuber中使用的OBS虚拟摄像头方案切换为Unity Capture,解锁RGBA输出能力,无需绿背即可直接使用 +[视频介绍和安装说明](https://www.bilibili.com/video/BV1uu411r7DR) + ## Requirements ### 硬件 @@ -87,6 +89,20 @@ https://github.com/pkhungurn/talking-head-anime-2-demo#download-the-model ### 输入输出设备 +#### OBS Virtual Camera + +目前更推荐这个方案,UnityCapture存在未查明的性能瓶颈 +如果你选择自己进行抠像你可以直接输出到obs,如果你需要RGBA支持则需要额外使用一个Shader +下载并安装StreamFX https://github.com/Xaymar/obs-StreamFX +下载Shader(感谢树根的协助) https://github.com/shugen002/shader/blob/master/merge%20alpha2.hlsl +之后,使用`--alpha_split`参数运行 +![alpha split](assets/alphasplit.png) +你会看到这样的输出画面,透明通道单独使用灰度方式发送了 +之后对OBS中的视频采集设备添加滤镜-着色器-选择你下载的`merge alpha2.hlsl`-关闭 +这样透明通道就应用回左边的图像了 +你可能需要手动调整一下裁剪把右侧的无用画面切掉 +(看不到着色器滤镜的话就是StreamFX没装好或者OBS不是最新版) + #### UnityCapture 如果需要使用透明通道输出,参考 https://github.com/schellingb/UnityCapture#installation 安装好UnityCapture diff --git a/assets/alphasplit.png b/assets/alphasplit.png new file mode 100644 index 0000000000000000000000000000000000000000..1d045526eb4f216086870eaadaab3bb247b6651a GIT binary patch literal 139513 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

m$qCgg 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

j%3UC<_+!+5+?ZIKM7Z0fVthlWYp#2t_g5{! zAM(Mw*58MjDZtdPgUBgtm04*J6V24XotQmYP7H(D(GGc+N2i>7DI;3nXTJXYNfU&T|5 zKF5jrmylQ6TrH01J80yoZQ;^W-6o>hKSU00V(Hf(!4$h~(JEY% z$BiE`NJavI4N!j@AG^s{lK-CY`C^PfMJ;$kA6w+canMK3!uf|Vg zm$gg}%!-*%fFUP=J{Sk#fWzsGzSHhYr0n)__k%`L&vHHvYy&^(9+1Xa`@d`$+vlI* z{IU@{;@DStn$LDp<&5u!2eL8$d5711i|1AS`5gP@=IE$A{VmI@Y6A)RIbyPXw*K5v z&#nii>**d~phb-}{{$_y5%Gy*eR~j3+(1QOm#+)xG_7yF^Ei~)_Wi4$SdZXHEKs2~ zQLnBqpKj=BBv14%-?17A{nH%ptH&mIRLo_rTO~&WDeC4sAr*R1imX3{J6e7S*PCb) zO$y$jLnbxnhQv1rr-}wWoEC)M^dQ4AD>rMTOBcyRHg1(6?VEDl3OEfH?I*?QH<(tb z(wIKqv7d_qk_rU>6h>c6%)6mePi?KNDywZl%8a_9;u(+7(l@1PG|<9K(wc2X8L`Ec zp;bhI-od;|*F6?iAH81ylc}*H2z#-&_2QS2a# zW>s96h;qO!WtiExbJL1{vTqaDJV|%;a&L`pv2nz{x@ZnY%W|fAk6vEDzwci5u=nIa z7!X97HjMk}R%uZhIQVDH9cuX^T!bgz_Xqh9nXAMbr%K?a0-;bRYeA&l`0xIZ-KS|v zwDF$%q1d0*UmpVBOEI0^-HZhz{)eW13j(~)-R|z%3{LTrjKc>_1$3e#R2kn9ns82n{i~Cwj4qc%efLUiiE1F+!-!n^ zZisP;Z^~cYd9(K7c)VZwjgn6hU)+S_n(oQn5O#Kpx^MNhIYnjjX^&Upk}!wP#dV>$ z(HAqZ{BqFu&eDG3GUIhkV$!w8Wf zYuzfH?xx)uuNq5`z&7|V%)~21vyA*Sh$QX^2hP~QfUw>BJx(*~#Ph?nGT0)U+DG(u zm$dMZl$44@`d5%XOJ1v!=~3LW6bN*^-@UN>=8vYSzUMC(@Tv1ZtXw<(PRf){;2TLZ z`_+hR3eNHy-za#LjqlSR-={@&Jqm?b6&baw(fF%lp`RdfmFe-$z$P$s`Ujz-g;)T2 z95*qF*YIE7Mlc_rbdYPV2)%PdV518;zPz~ds#+(o-`Cs4v;7|(=3Ov7i8181P}sNi zlg+qC$T@jrN2}tC9h=T;{COUt2lqSE8RgZ?8JXkzI@*+&-^hT7!qrC)ymIYwx{QHr z$Rg=fLE@RR1|d!HymO?R`5d$Xm*zi!`u4rh9e%?|Yl>)DT^@;o)8al+MB*k>JInkI zozgsn;h3TG22F^O0+s?AL8+K8hBGf(kqTUhpBV(GZn*gbvIfxmBcAaYIsCxbn)VhcJqm4L}6$Ww4+CF8t?iHAu0LDf?zy2i0}gp0B^Am8ZS0e^=It z?GWu%%oYAG(p=*KPh`unMAbMdcwQZm11(k8Qph)9BvAtZ6yBR+-`8T0zS$CBHESGr zpbxyv0qt*_l^vjpct#VQL*6@T@Wnh!QU>AfF~-I7r?i+ z&RYnaNI1loqC8b-^wrlzE<7Z$rsk&RGE7vPQjPSCEJ{-|{>HrZU`3S# z=c*APAXDJy+?>^S+moggx`X{wNQEqkN?8lPBZD0u$lCt6tR$V;MNfsLid06 zYu6uJ*O@;ZL#qD~D)FZ3v?}ABn&E3_EAgvtm7s=vt%Mr|3lq|Zb%ruAC}@Mt>X-QC<%)S?Ko>ucD7HT- zhPp(^t-7zKfYCW?@8~HSKJDp+Vgh1^r2KQ8BmQ(z*8o2nK6Y;uC0YBLqlW&uM>ini# zJ%v{DIq^R6zG2lJc^E6}ii&$O|8RDJC{nv~@xHN(F}$qCS*52bRap0;1Rja)1pqrI z)-MS|15&0{aB7R*#-hElp(iI~L-|WWmU~k|*@%v;$}D)HU%gsF1iWd9LBdgGmIZMA;w$>gAS4u9KY@1!XT_h_UsgN%HL?U^I=W7 z)XuO^I{ZI40?#qN^u zzy)ObVCRKRx0QBfQ-~dBNjWV42jLQ=dnGAFc{uJ9e| zK)5=}Qxd(y(Y1EVed49*tZ(==XH6?B&d*>W!tg^TB!_PuJJa}+bnEl+@<#!>tR3#8 zc=hpM->z(z0(CNPoHeQ*M0x@YU1r~)3Mq3V6Ki`*5dPhS>sMKuBLDlSQL7ggqd~w^ zkFFZr2_cWq0T#qg&Y=7d#t~^0gKv~K@|u$~){r_@IGt?68#J>N1zb>=7^F2wt1ndo z4HNdLs3=c;-|cy*Zj||ZKMvWEoK*vCUi_KKIHA^SjdznN(YFM!9OiPf9@=!Yt&4i( zdvLvAuP(o9CVu#T0n-{UOx80Ikb!(m2P8eRe-g^$FL7u8?v0kKYmZJWjVj*?qaCB_ z`rN^2nIw-w(mx*lkLg4Jn)6I+x&q%^!#08ToWa7o>b{TaaFZ`7zAq`-+SXB6Vo#kmrco3|v;?tY0Es`J@uh4R-+h5YIc&1q4v*08wf|v#- zH|$yP83EvSj8()esn^~$YtcAa&7Ke?CQ&-@dPXZ(6^eC?&YWlbRG9OWfw6b&@O^aU z1TyL+1ue1zQ?R|Sx~QF_f^i-D+%dogO2m6bhOdT2=vG~AsR~Wb4WHWhX7U&6C_}~= zCPJYs?do-dewfz4OYab@Qg&8Gy4G)4QFQr_Ly#~@`?i3`>%+wyg#WL0q=a-D9D#+n zNkkPrk_q|d;V{2PE&Lr{u8881@E(nR`qqI&I8*=o2L+g0qeY`JH-#=n;xrUNFy#zk z^CHDnT+>}hMV9a~+7}rz)4JL(2}r}p!-OKCg)@3poC^N+qoUQC&CM5d5#ks^=1Ec9 z-9-E46>~!cwkVxs$O~QuGT3xP0SXDQsxW2pY9%9?5yS0Lc~V(1JGpIK;ic+ z38??OXJ!G~^ji10>@t1|GJWcSXhHj>H?F=wSM_RLv2w{-)~PY;tM^aqt=^9}*DGI# zgN-w|cL)xE&+1)zPHtXzsEBkFq-+y8JsJ~LnTfk&oD)bUf)_>TYRnG z6UPyiF5?I;0S4&^F--YXrZN8Jtzq!OV|MZiv!O2-6}GRYxgKBjTQ51&5Xo3pp@T5s zs$NQ=s2t5~*&zIhTGJW(-Z~9cwfsvx#o$YF1CKu^kZs-;fUebya zo8a%<)(u-;IOD0^`m6)QY0%-$*f=cald8YV=g(is$-jc4p<#a?(bY2T9xLBY%IES`&Mq--z-8ElZ<5wKJJEx(G%KE@CjS0g5MHt zfS3X}UPK}o_o76NHOe9b2fJ2>01688##771W4SI=uot#r_i>ChK=`!?$xay9dsJzz zo;a`nCO0M`+43Dw-;8B;L0?MIOn^3Zgm4Wr=H7iXKH2l1jH=a7p}Gj;{{Fcx4G&o} zq#q}Qv}P_vWT!EX=cZX~NJ5H_hL?1h7kOM(>2X{;{6;g7|BzIR%j45#-1Us!g?$1% zwfo<6*tsXjOL*KQzFH2g!xICz9`a}Oxs3$rhiYkQz1|Ca-P5U8p*F`b62=l{jVHOb zj}d%P;IKnFkch8S7cz&`!9;FtcVkJJ%q@g|pm9PBVNBF`HjP24NeaNvf;BMIfiP20W#}G=ztaxw{~#am(nyPACI!ltB;%P?3ZC%0cUd)XB&6( z-4P|y3`*%g#bUZTm4Eiq{KmTW(e4~YnST8?{eLulV{~L)*KNhNZFHP;I(E{rZQHhO z+jcrhr(@f;ZQIGM=l#YVb$-^rebzo}%{9@x_aT{qATC3>&kC^t^@x|C$s$pzI9Soq zM>_hjeU*V*!a4VL>ocMnKiQqOkLKi%TsAMjFL z2a85|(eXNw!6e$Uy`;GCeqch&z6UV{(~ko8`_viz(Yr=-sERu;Z>xjtBkcQbEJSUo zeM?kdn=M~XdL=RAdFE}B;KKQAivUREwMBwz!P?3V)v1aFvpWU^c=|pAi#P7;1W0|V zkGoyCSLovH0SDRAUHADK`A=?7)^MY1k-rXS|F7je$cL||{xJwuRToocoqD7V{@6gff>{8gQe1fqOZqkH* zefP1RL90N=y?9)Fysz!*YOD{j7nsuQ;X#GMwFBKwKPezi6%CaDu*y-fBnleEe&O4x zG#uU@yE)!78^+LuTmD;LvhM2+8Q1knY^_ zIMT~~-E#Xf=~R?GXb6kL|1l+vf=*ODEfw9&QP!_tyn2C31_S4dVg*j@Sr>Oe$}Dzj zJxC3Ujn9!wA*RN4l|_Gvp%}d-S+~u^Gp%yu7`UV7a|ZTto^tPDC#9cZ5OB z+y+gW@MzD*Zi#yJ!+yO%o^`15F0$@PjAl6rlWm+4x7 zyHLFp^{-=Zs|wQ`6P`K|M-`R7d=@b=QE(>nW?Z3OS{hv)5NNvC=-hb(WV}Z& z9uS)t%c{RBe{9t{T=8l+I*l~Ju`y(0_UUm)lR*hUr`Xrjwp&1hb24*eO%0*JHstdc zhL@UBK#+{nTS#UDr~E&e0yNXvEL02>{~2j|6;2As+qY}3uh7KVYoE9+nA^!`PfbtA z8fCDYG^xiQz+*lEWj^z*_=%(U-%ou%<@o2%nv@2;Tei8K%`^5FEEY2z9WjKVBhXHr z#cE>J;*n8qf77ju#~0n&bLGe*dwF7ovXLYF?q`1ca;Dt;)0`0QjWVRlRL(SZbpN?! z-K{xUa^I->6H|`#xlS^O-GwV{lss_X6D(D{gfU#M-3Vej>{IoFF|eD_-fkOY@jl_} zAUN(~kZ2T&uYX07@8R5X9Oj4`2X^rdY@$aqMzus!ioOI6uH;O#rAg)8@B3m^?*%E& z7*2UglaRsnW^ZsL%(c?)+@Z|uf2KG<-vEG7iDE^L*WK2?Q%whacRj?3sj07BqOaZk zIR3Bq?(g^W^YeD~ZOmk=Cz#p z>!VK-8$LXgXHdXM>lYq?PnZ}+j9m07v!rP2t(T|J+G)3CNB))?6yiw%uPki{HdclX z|FcYiA46Of*;7@=%kRua>_yA+_n66#Ypk0E@Q)@&v`A;YlJ#818|DP1fpjq2;Ma^@ z_|pqMq6y2XZJF3v70^ip`2=zxPnN1E-|GMjK6s`F>`Q@~HoRk|3(y>1&n!k7DauN2 zx9kt*nyq;Qu1{xBwtn8_dwaK7MVsK@$8^?PD8ivjlY&U35&2tKC-4wnRAipt*_bnB zvbx5a?=y#}L~{$>$NS> z$N^Mt+nF+=hfH-eL)D2~iaJG~rbKDBAc8a-by(UF4qPtVGry^gg;2Vg>*afCKb&~> z1;AXi8hgNkErPO5YNa%k6Z{aJcwqqiYO6Un_vMKkcDIURKmxel*f9Gdb_BP1dkjl$Dl7-AlpkLX*7r zk8-#x3PGyT{HVcIvO)%ErW9@>)7u1M1WbSWV%hiT-d-)NN>~Andh8b$<_S*Xg3j$ zkaSZiYv9{2+d1ob`9V>;Xu=ze5o@sBZ+f}{RHu}1w&KP!v8AZppAaP;T!r%*UjWc=RilK=X)|6ruWWX8&9ipcBopFNl2-t&M3mEL$Q=lq4tRi6F#odw5ylBm_f{@!!oS6+fJ*&bed zqHmpieuxI&qv7plFx!2gr_+Bw`yS37C3urnV5~@pVg1WZKhpQ0-pAlLW4Co&6CNow z(IZdO@jD37)g}qh(}cU^B7-ESh&I-hkon zIwW$-F}F{|kazp52NfZIxkti-w%zh59BPu+`BC@IrQVb#O|MVAu6x!~W&W>$Dp_s?cpxObx5-*|pP#NZ<0}-|~hr4ij#mvvV+H za%N8Tk~xbx>U5*#OjniGsTOcyVag25H-@=bM{rJuhMfxMB@OkhC7=fv##@g8U8sWp z^Yf}}#;?=+^YVGIAN-EFw<{Jcd6WS#?DIv#(X>Rlz}ok7 z&)qCi^GB2lF>L%xA1%&Xe^i?%jXVeCM!&!Fg6>n-6}KIDf}Q>w)Cq-T zw(e_u0>ZjAn)FGLaeYOeow>0kvbo;&uQQ~mqBJS`^6qRr&p}waZ?~^LAOwP*Bbm2WVe0?S|pm;m(Od<$@DRO9s`Mr4hfek4EmfitBt%_RTsytGXIn>l>HKZHkpL?By9?oe3huhB!E- zIue-n-FBxBwd(kYX4bAZJlsmxYft7$NBdjAb2On7H|nJ5t8wCBR+B~AupeF!69n`R z9y?siI$CAMODYsWlZuU9SLB*9H$59uMw=|yF|DvlNg`ACM(`M}z8Ho#WA}S>9sIYk zx)OKjH&=lRi54$>4&RTLkB^VhBq}T{tnTN|YhY4f)RQtZ8K@WRHt!sw>onpO(Z%b! z(pkt+A$Gw&@itX|)m;Z@OVOwSk4zg?w1_})pKV}#dNFldOv#Q*P}Y0!`%cJa06n!bT&}xeScSC_I0^^mi}ezBsCo8` zCPv65Q!NU*t`7|U(-Z-?fo)960pLfOe~b?s2+xKtmE@EOfiKYT@|JrNW7hx;KcI& z4J*}cJZP=5%I}jBs4x3JP^Vzk+?iKqIgNP z=?nwDpo<81x~4#%4WM!nSbv>N66sjx@@{Ty{Yh(HYjotz$;#0Rm4FWm&$bL(kv5j_ zhaRtqtmfYpcqup?ZE9=*`#Q8r<|33`DCZ!0 zP?-1AEKxY(d{jRC0aVbunJnMe%kY1cr?IiIG}EZv+fmid*t9cg2CvJz6reyv)$-7> zC~=f>I@cHZo&?7W&KdL{f^wxwftbdlm;~l8kVJfuek67DV#*^VDYUjed4BhtDD!^Y z_%=T*A4?RY1zTDV8!+K?k?bdA7dkEa)waYIvS&{RZ%>KbkR?4@!s3pYK|rO|!PnM? z^gv1A^+IOD>mFL1A26)P)5yij$);-cj%LxcM4QYCr!&Gg<4`!$U8uO;okcZ0$KV#U z3^dsya6i$wPu~LcvCi1wFUE|zu`tKx&V_z(maE=4V#h~}>jlyDsXCJc4Z}pCvdkq- zlQ}vgs3XeE<7^m_c`EI?Rh8PdduN*iZx$^k+|R!&u%af4ax9I689pV~Vs&64Q8s)K zXYp}tC`>}&D2(?7pAu{sY@TlYlnA-LF~Qth2ta00@b4AAEk)`)B5dEXQ(Z@o`!<`NhHr`R_*UgtIZV-}>>R|40_v?q zEDFCzK3vnXb{dQ;@^B?z&T6>cOd2dnN9I04GDxw6sX>tnKTjndS$X#Rv-qhvO9 zkeEShr@Owj(#J8}KbTJyW-4VV<;a3_n02T7YIT~s@>;Kr%MbqVlh|=~l<77H!YWR* z$F>*?Y=zCbJ~MmJpnr?avuJzx#golS`GINaOr%fFz1jra`2#+95tlCNW#$k2Yz~p% zK|v#}T9c|;Rb$O#%6KuOc!6Y?R=5+i^DZ&rtYkEC=}Ei3A*%akTC214k~k_%z8JjH zY6fBXj3M~KO2`NvR|E&it$)9$6?OXPp<$Jki(yLay}M$ZSoN+xX$g<*;UzAuYVOO zS7HSnv1g>9xEbNQ-~`^!#w14S8m|C-P6hz)QvoAegmDI>C}Y6V|N^@`Tu_@V^bO zeAOxjQ>B*{=}{b=X)TyX>3`t*Yit-c!uv4_pK}{Gl(l|{rRRCLn5KL6Ps=>Rt7gl) z{^4YJYHoOFO|?--+G7!XV;*jWKoGPopdmVe8_P?;L)tiw|IU8%ypF{mGFwS#V1zM| z`UV$zXFFTk&?UG|~Fb><#9RmY^R(m(4kUsSvD-gHB6vLF)3x2uwzEufL*)1 zZ>mOJZJ=EWt;ri_s&%1;Aw9&3q4r0rr7QN zuL3cf(zV(ZkCd}o#&aaeFgK9>IHk)V%5ClOc4^ucVZ-I4pEn862pQUMyKy<5U#)3> zwA(&bseB>NZTp7dXOqqTA`$X;d7HnkJ<2zU#?y+Bu&Ahc#7z$saL{QQ+b zPSC=m`1E9}9XZ26V@3Tj&(so?b<5sm)pw zz{O?#mS7~Y0P-N~dVo84)zZu$oE^{i2i*CEXN>Fc0jK-yq@VB)!@SZiR?6kun zjDRfWDA9ZP>_dQ5l}044iP*2-)v*!2 zeXl`RU>ogfR%)6to-|287A<0AwY_E$;_j|-V3U+v9sfz)Z5K34EFFAJJv}O!(yHtx zj3ddn9RH`)WaR9jPsR@SS}n91chHaH=xK;cwWoVsDC2XvSgGf=eC)Cs0`6^W$F^;H zPG*_Q5GnRUCn;Z|#{eeEle4B!QciUQOt{rhGf?e;?5`M^pF>(&i*`y(NFbo-QD!va zSkC3je`Z&9$-;my)UdAaWr~4*y!0TPNy?$R~CqKqPCNC6bw~uwzduq50q*MH1)4=*|kAdG#zkjKq@igG(NR20PHe zBu}Vm#`1{|w_YO)3Y7Rr0o8=fL}0?NR|`IP2!+m8{*_(JrS^JIIN@~lRnG6pY1F)Y z(~_9F-d6xk^JHhs7+OtTFVEPeSQcd7krHv27+Gc@B&}wpQ+gDN)O=Yuz@0QSh>4-G zrCN5n05h_hg)z5KymSlQD#>3KxuIv9@@4Alu?}`j*4ev|3Z0Bo0{O1J!raP6VyLdT?J)ah6 zmynfv((KsUezdgCWT2Mr zSB+-gtBNFtL*~TrhTtb)68i_YyV5~cyCNi3Hed3U02NEf>ruE)$}Yr#59gk9boAJG zXWF=!IEqPEFpS6Li>A*pg|e0a5Mwcfz)0EqHZ}i_-S%(x*Ye)m??#9sZYP3wHI>X<>t@6y}J%4xte>VK>wuQ3o`&*Izlc}g84 zpe}I~gwTm~ILMw6uQPAWaqaWnqG{Wynz%Lf_%LMeF^L7gj3`x~@)~wA3A%tZPUIq+ zm;s}t;E6UX=V_9+oIth^3G-`EOYO~~$A*J2Qzu=6>!0)E*_m1H3&)JRjZM|&S-yg9 zc8=e{ZkV3u>1)g+y))3SG5QTe>1rPRGoT~MlbXnPEL=khUN| z{$T@5dMRLkV4eNJip$lervh>UK}#|||Hm&%`N>=o=b^InG-a$AQw0NX@yX)(@(Hm3 zl%tPH(Z=h=fcce{5%e%f{YXzx3#Wt~&Zbj+4ebbs7%)L?P<4z^tiL{elg*v#EE#f4 z+34YFH?HBVsM~+4kAUa{mjqLO?6R2iZ1T=z)W4z`3DS*lGjz*E(IR0w#)o#^lLBN( zmFlw5S!giARSpXbNQ>~pgs+Fa52HMV!O20CH{+`JWLuNcUfkgwKUS>ZOWYvnH_ z_A6Lr6$9+BT@v=pyMfwB!6#|X3k0s~IzR{g8ryRE|J#zsf^A^5_FwCG{h=5R;63t3 zdUmK--*>&vIs%d$>`LE0Az>+#hL(nHARj(-JUj|n#LV#HkQE3|OuD&ty5`hJIYeu- zB9X3E-XKPx(h)+8BaqHi@+S;ibJxGZs@GWjl4EF{ZP*WOC_| z2^B~kN>aEunJ5!uR525+4HMF#<8Pq=YAk>}K%^*Goeq}`iRgss9!%lcFyzWBQ0lPR zD%2P8y;d*WcGPodJ ztOSA8Mtd_=X~mwlx&~2ZoG{im+;#$k3wt`afKlV-dFFVAm1ueut_wJThnH_>U>lb%XV5aITBRHwGy5~SdVnL z&k>D3yf7}SfL{{N!2e0;en7pXpbhEEWjV)iB3>{zo1Hz2@*0Ae$w&|*;Rx#t6_}$;XRo1Www=GLcOOM8@EGsRu zn!j)I+_pQN?ibSJo_E-={4eavqvU9ETiY!utoE!W>V#ZLx9Y<2(h4%%@*-vLM>m?PY*(%iv9Uqay;cR zQc4niXOzh2XXj&X-26CS7{NyM^6{4Ed9D?T27xFo6f@|N{q@JX%ZrGC0O(p)Rg zWL-8!?xWEbM6ycOnlmY9Rg$TT*qF$#8^a7EHSn#6vc6sfZg8whBwA9#F_e>Q>{2~(S;*dEO0@^*W8u83^umlx#Mt_^X=S~rvIM72}Z8esSDpgo&OZbHl zx}cVawFc_byVIQKAPYaE%j;xy`-ZJoW+h&drgb@*o8E`{H(OdK=j88_M)%?KHa0qL z?#62$O84DqRK^Y+gqc?)z)na&bABre1-g4}h8wFeLljfv>g^EHa{CuTD^xj95sSa#bm3OC?dphB0%LoG%&ug7?ah3oA@G zdBsD~0!0ef|8UEtCg8!1KYOKmr1T|Fclsxnv%9oDjwp60Zak6&ZiK%)F4oFc%aGgx z2R^|u&aESLx^@AAt@hCVsEKe_=Xz9k*4tr=2ff-OB==wIAp>2?)& zjX#w*%@dv`w>;(qaueRLoW~apw%3!@khl7kRe8Z@ z@CTqUFU5I;wE?4xHHbMy`SuL@BOv$dM!iK2(a3 zqxmrIMa!6Kwhm*O;Rx+bihSWpy^tj;PKZ^+M6GLEo#5ol_JN@pIJ%)4nD z+6&7OkKk>Nw7g;Y?n~z|v6Xd*rQ2*Os}pd3$3086r6s_8kBKeoxeHBFc`^qGzVA_6 z;N5F^Q%9tT`O0~7CVhuI>KsfWYv@TeEi%=E3Ihvd;2?iZz^T|LNS9zaf^%47Gx&4F z-^DwF9-kCc+f?mKy&?mG`UbzNK*;DH$J$>0}a^~KnP zH?v=m#f@iS2^D=M4a>p42IlUBmi(Fu4dyeB44IQ`m8Tg{*QHC_+F0ZA+a*mRv>dn7 z1DI$NCTNy5DtBaFm=79|juf}bD#S!f8`30h zpK!HXKF6}3<)JdmpYVowjOY@8JW{pTT}P-}mrDN2hrhH>Z6@u5t-Ro7;|Y-Zu-1*E zuvN4qXC8Hva-3Yad-C9iU(=@CV`G09D+D4}*1d74itq^!%eg02qo6?~v%2yt06EmR zWvOM08suYQ}LN6TqKthTa&en2U zqSf5>#Kr0Hug{)Cd3(KvXR|*-Gzh}s6-nY5`Lq>)0@)TZgse*3hc{G@a$|g_dE2F+H@+0h)w>xQ!ri#BPrrnbi99!J2>qH#jf zn5yEtkJ zQh)mIS#=PqFJoA4CKY3{=E1iQ$U%dg?0GM^A#WUXvc`=S%4%NR%48MazGp#q}gztXvS9)HMc`*YP73xF#-ZNLR7|p2TyJJDhC2nkEzJm2j)a=jN?|pvzlv7r&Vr)b8 z*e66pH>6@86g&M-ET(46K_{j;#TEM<(Chu1{!jg&mRa^tOe`w*M#oq^G91zK{BG=* z`-qYD=IzCfu)C_Mc+u|pc_E7v>tfo-!Ma;4wa8XO+bd2sy9J{EdI?#25FU@EYiW1Ladk-yAq}PU{-f;Y*aYheVGH2MgE|mS}_V-e(!h~P&m61p1)P*>pw*Rr6-tgQ6S2pWLO zPm(@xz!`|EiwjmaIfz;Mk-pdELpar~ax^;cKk>?WNen}s561{EQ6EKvQDPx^*M`kj zcc*tfAla#iz(te5oecc>BwvxUx{V#=vjphnUOHE| zFPNZ{Vb!;Gbo0hHFS#tu+h3Rs_By+Q)otnzqqlPw^=r27Ha;=ctnNj~1#s?3heT;e zTt*t&_*qwO(jyEjf$JMk=G>1xz8C&s296?sF)yDcvr;~bfeG^oL${C)Z>6eE?z zEQS185YFL5+xT@N|2$olBxa-00BlVOs69cv{C^8y>F8<53?yfVd8aiNwQ=5vKRQhGG0^TC<_&>GUZF3m&9$zoCeF-Cawo577pq$wnU{2$7!>J+yN)Bkjft0Cv92!FQ1GHmDvnIw0pTGZCe? zLdlaa(e=EQDG#9g`@hN+YlNkjBZ7-1y5nhJn1_pO{azlwpDx+IU+ITBmqBjPNM>pY zm2n>-$>5(%8$b|fEDp%|enrL*UHcq<1z<26h^45~Z*pz5E2aEQ^bE6~3WXt}thLc; z>#Bb`m<`IMPZS{8BJ7lH-aa3_9d=An#3&F*=I{izNq$ zj6c<>s!L;ZPEtoW^7QIx+{_iTy)nVniekE?!#dg@#W;}YEEr8_j?F@z)qT6B4fQTA zvB**%{ctdW_5^uA;WTCjO%*1piP8@vqpgTk(?0>sP$XpQ%!($#zAm@7fAtio77y?xBwSMI4riK9%K4L%hE>-aKh=%yuhXyY*_93-1nL{vkHp zTSaW#+J{>v>(Lrz4L^r8*(*nkcT5YZg-4gTC*+-hnBK0Marp=H0~}YxRC<4RZ(4)6 zq6F^w8qG3md=1aL#yupHEpKxgE&U!F9VK-8VGB3WkcyLd5V?_(GgYo&SI@#^5vmWi z5fDA#Kt9o?H|o6$)K+(IecV-5SI(UOyM4g{TKjDJ%&@V!#AJs~|HC<_K5l~9GTK_6 z2%_D+X{Vha4_eH|IucKkcVHA#G4{CML4$a#_1#^(DW2960(W4~oK&v>sGxOIE(%G$ zFr(mAOZwjbS6P|h;-OD5cHaH8b5dyKR0kCHPyZd*DqfOY5E;IUy|`T?mq;?#%@Cnk zqH6;$A%bAcs}LbA=S(aNp!z+%9wdLIGQi`n6u%MwcRnKEQ^3B`Ow@veEyuZSQ<<;P zf?T4+aEDMK2yhAMhG18_2ld9YZBhp_L08Ki& zQT=DD*hO4#=OXMCH+f~DAl$W8U@m2Y1x2`YndrdElu%d-F13crNzPl@D752e**zVS zs3$(M&(12*z;P%>Rum_Zuos)mh6PvNbgJa5HJh+YogJxc3AL1MBlo6YcN}Oaa^h*r zkV&-NB6d>q1MO}3WPu(t%Cp4(=K=stwYAKL1WcSPwDs(tiJsJ3twuCeR`!Cdg#~#r zB@tcTI&0E^#%0@ICO+pvRjbCon1Yuq*s8qVtJ^}b;>PAQXE?1iY(^{cUJ-S*u^IOw zv|b*ZxXpVBC*1y|hp!Hm3`I2q3tvM|r@ggt){4zuz%VqBIY`T0^b!a0{a>u)PG9Kp z0`O`C4p=a#JxRxFjaE{`2NM7Fec387?k(RD(G%}1nILwFq3L`HN3wG0+i~8RA!-_) zF7N;_^~C9t!5`EVCJ2F#Bs0@wi7MT==>| zNqY!lD(T0uCzqvu&pZ3FRrA2q+r9{jL@20V;!?c&PO7eMf2@LbL&sd?7>mYXl%U%L z#RCA$47@xnU%`Eg#TboqqSP%5Hf}!BI?k8dgyIIh=)75|Y?-umQ+9}YUW#`_gvy#W z-uf%(Im83g{B80y20x?*L#!5g14!*vBRoe=rj;WO8^Q6>g4ZqF1e>d9A&$W8BkUU0 z)1v%0QNTyHBIt7+a1f|!T+@&>P9jZ4wOpMEJQP5^y3p|x*MgzpMOFICx33Y+(YO6V zJ``sT@{8JtaK_Ti-^TbmZbNE2P~?Wr8p%2m@@F~bfX*X&KNqX8pqa5z8;A4cyBBzI z!^&?5BzttU9Xx`i)8^5q&eD6tdiGSSboeb7&uc`BBHF#n)@josTj^x^6I{!- z%YTJ^g1F2wCnwC~AL3o|wGe=Hz&IkN6U-y}pZid9a|ny1k})t{x^es9rd$$yOwq$g z9v-}sgMAaHjQhNvf4kp~skW~YGsddE;Ksy0J$cnM^>I%4Ubp@J{Z<@m;{^3om;cUj z?CiOz8g|$ln^9PjFX6_x0)_rSr)|Z4m$A{4wQ$bkq*UC2$`EA@C3QM7)AMVLDb1m zC2^cZi-N^t$#Q@2rHq#-O5|hqGnq&GE6P_Eh|qtF1d7vu?9u6}jkCd^1mcIh1yfICr3lj>ujC8=-n5K1NoaiT<^6EMV6?&Cx)7DN+YR;obQ~~ z^A_P0bft}V_^LqZmRh?gszF^L!M2!{7ZE!{3B}FrYr6cWgEqQeL*FBH`gkgjTh5a3 zBTL|vSm7V+T44z1lA4af+>j2S`{My+*Pa73Qg~oPd2Q1*Zo=@5s1AEMUy32~wm5z| zo((N8PdGVOG>gyTlJV}oZVl_UH^-oTJ_yqIw1$fZIAQ1Z=argMBP+_zJ14pZyt{)a z;Exc(hnzR9zDR&ZzR#qj*=>1$M%_C1!G9#E^K4nUWrl?bXRQCA>J)B^9*>2ke}MAb zW7GVVk;sn`R)<(H)CsbpXM|}@#qld)-DY1!uAHyRl?xbbsx1+GCKmRn%8n{AcP-B& zH$v#3UZSll!p%Ca6AG8hG!2`eM%y$0um-36a&y zcNu$|$HaVsVs<;ep0MmcEukIQHqG`1JTDd<1HOv1+@fGgb=%~izT%DG?T*S zl)0<);c*g{x~4+0t~?+)J-#+;&f_G875k4i|Iy!L_snzm!y}%NX4G7=bR1UjUv=GY zr;&be!?BQG*exBjIURo|nfw9~`|bF*xYe&BR!dM#-DOglv{*8htZG!K`(4|C1?>MvCEUcT`mIBja zb5>u>a{)gR9e!oXf;>0tw(0V6;mU|gGT}z;iqBiI4GSx)?)ubMko5`02|1yxU=i%P zPK9&EqFQa7$JvYSA&^x>@s824F~l-nYNwf#82>PIwXpIzOi7z6gDvP6ZCod;H)ghK z7c5`AV6%#mZSN#Lkn8wwxMBq9N>&fqe{kl3U<{Dc1m(N_a*|r<|2)RrJgy{tfg4~v z`9sIVvJLB*_<@3qr04`kqY$W~nId8$=}X9Fc7(7~1e?WjGaHCf+_daa&s6ZIWN~h2 z5U#QRtljV9XT0ljjxz56>EllTHom}AC2&ySZ9nL#awTW&8d33i<02-X@Q=CJThji}nY zbhG_EUdzz;DBv||mq_L56{2brkedexqej~K@Fl4BD@43!h!WDfH7okLU{!f=@=yt) zCFRW&{YTwoe84YY<Z#zrrC zmtroh^t@xjK^z~I($vki06C^!GX%r5al;-M@M(0BcA0YK zdl+Y3CD^GBi^FPBz#E2z0IfE&)*McZ71iv7hITcEpRc{0&Q}C4I;hK*Z8zB_uNGXy01mEc7 z+7)WjR4id$8rS?rA19^vF`%^g?1WNgYUtFNCvCh=94qfhHR&SrZdr(irsl6JYm>$< zhnnWBD>wKoRr6Fr(9Wr*R+o*r9DXws=6l&>Odb5dj`TMCcOHu+9%Br#k zJshVv`q3!`;VV}E(jV^dZ~(tIk}%pGi;U%DpZmw*a#Q!+Q;qT8?tACv<-C&lADM`j zFG2q|2Kk!|bKlcRq~=bblJ{H>&X>vg0l8uyXKLM`&x`?uR0giRjF5~V((n7e-P{W1 z7tzklM}J79ho=1%bFyABl8^F#ys|U1CdDa<>K;$f8`D1eXU8ot@wf?9LS7yL zDwA#gz6bg+>Tc51RA2G0uCK4^=={J?`axX!+TOOOyf5;ts&`z;$B+Btc_jxn(+QHx zWK1Ysc~lp)4qN#zsA?vjlWXAGG`HUolJLgYd3tXFlP&Lvu`d zvQO{*stq+FC39}Ets?$3gy9Q_ZF6S`ip&xd=n>P1m7}`vaC&QR!_BtUe}bRg+$_cD zl?lFNm+p`ME26SwfF1{-a*kqX*PA1S|1e$nHx>WuXq@ju(R#Dp`S74!S&~0{N{*~A zk>Wd0Wx`*)k1Gs|Lpk|kM)dt)U&?q| z0e?g=-sRF%kr-V>2@aA3#C;e1+gf`?oVj#lQibBJF%3%;{5tPj`e@l~#z_uZL3W8f z7i@u#j5+!M{GQwZ+ChoOo4wo2>1|gedEbe0G(_$#`JI8LKjkl>GbX0(HX8ybE?h9S z+?e}AYtkHJ`<{6YXqR^3+`ctK{cOPCfwiV4zuRd^7SsIYKajgST}AmT^mD#_DI5~t z^CAgZ(gwe?zL0!=-aa2{AYPKy%hDqPqZG>Zr&WNHSru#UXrOXB{TxSnc-Go?jga-4 z5B_<$S-1VMv39$|wT9>9*I6Uvs3Dg1JKFy>2LLRY>j@`MW=~kDKxchlps(1OFN8CSs!We%8Mm?#!z1N_i34jJS1XFyg z0Cu^n9H`ftZET(N9J&b75~$W29IEkykeI_@W=F{~ZxO;7GaQj^NoBCd=koA!?)7o| z`wK~60B=3b0XqZbob#9zXeswPfoVV9nIyLmiHphh3kg4;#`NoXQMJtYdCBzf@*>EU zrpS-!);aY3Yp_PfF)dM#NN~gBS+-^?JfWT%r7S+^MwSoz_7?;(7IDVKEbk2ThznTY z6o%tUWkCeA;AODP2m|BW{BFM7s5M*4Xz5EV_eL#`Pe+slUw>kMWM1x5TfZpU@lZj0 zGZ#l1%cn*(G5f5eDHIM+#8DHCV|8yU zO_9FfSPQ4j4S~|qGVv!6#pWUi6V@F%(W%I&$4FS_q~#tYO7NXEaQ)e|L#Exik@fjqFMPpAe9{^ z8v*8~{pszz*6-SDd*2NtjS%^p(eHKq{rQ^KbH;9(0=N;*ld{fhm%Ih%NR;Lturllz zB4wa$srw7&>Cf?riu{6u8x0BYQFMi!0oe)0F*%2z3H-KiAby0$^cA)z3ct)v$N}@z z7p-G#oYL!Zz8xzuE%|%DGut|j$GT31_iv|*+2{e>ir>>|dKHTC@Brk5R*8E2{EVLQ z!E*wioiDQ#r8q3gw6~`^qP?}=!PX}y3-AKmYidqnl9H5y%*`ZLLlRY_nfrmv&jnGz_l-uP$DUyWIfF5J-O!n{#Buev5(4L7?R6o}n8}9E7 zjlHcYG>+{7`bWh_c`29u*%9MN6CU1W%&OPHFlcr-^Wd1bLqrIJB+6JrpFo-E* z`M+&Q>^SVV;Ol%HEU9MdSU?}>Abzj(3{J*4le#=V1$i^aHNxmu(twom2u`5<<#o#| zIr|f9*GKLVY_A?j3;Zy=7oL>+GA*gue4VNa3?s&_GpX9C zJ_EIhUpxTqq^O=cSz$U13`oo2WRcuO+M=FMacajpEs%FC$yaB}5FMf%KncvEfd4j2 zA?dadvmV1S^G(0?W4>ccdtPrG4aPDo^u9#%rrm;8b;yKsZ^zG}CR20pp&F<*;Yh-8 zWWMnpCUyaPCdjW@`w4-zfTCzfbOFXrTTQw&25X%w7f|aU3I{{7JhQ^;)}U13ol}(jFfVS=XOm$#nr2zw7>Z zv;}0=o#sBJx!c{>D23s5^1ox#K-K?yy|V*QJ2gRhaQ_p z4b1ZT)vsQ>c=2aH``Pb)_q)?melaOHsP z0^$WS)42?3UcjwFljdh*5EvH}3I{L~{|&)?Lw3i|?%CFaw*!2q14vSH0<-DL`f8zE zR(>8(Y%Hqz<$3Jy92p8Q8fbLTF}M(U0ZCm3XLd>_K$!x>Aaq>fl@>ySPIlFgjSg(v~gxIe{0xag1zA4K1* zw@{z5*>t{$Ow$;`@qXbFrHd*Gn2yCQKk0g@oX1i=8jN-x>`VruY(71WhEdE0y-}my z!KFv&-tzh{xa5u@ev^a}@UtvHIG;;1Y77m6z+VQ$FYZu=PD(@we3~s3uHL-KC{v6? zN&P{OIzb$QsRe3CcwZMzXS2~XnMr{_&IDb|P<@nL2m}9cOkRK9PU6!FELc4uX1ix^ zyAW#+GqJ-oM>5rV__X>|3$96x2o?MN#ju>9;ZMB;yaY}m0T6$+T0I2;U)4)s`4Ygu z|DErAhy8DV``hj9?Kj_ileIsW-^`0a(Zl^0W1RnrUV_6gKU?yhDHsq)B}1@qyU-Po zmHaRGf#&q7FC`ZHYtAWU_Gaa4pY4AXg{s$pPw@jTjOD+(NO?I;!5m zg(DJ~7>ZO|wi$Fk0r}Ko008w|<>sAq7wqk}_>aele}&JvH9N3M&nv)`z_L{^nsdtY z0wQh3Yzhh(V}8GS`O5nGxju2I@%aAk-qW2Y_`k9qu>--*9IlWCkg@`F-Ah0`Tg-!K zkE%6jAz0A7!ToZ1wOlF}NXLU^osa;s(BSWX?)+*#p8;0m4|C_8+l@XsrdpheRD;zG{ySl_E!1`b|A#9*nNW+AtUnbLjZ`5jc6{TTXfmLKjrctd0 zc4=#)d~OZWKzt$Zevd_#)4W9t-Aj`Lwrf_#L?XG(QNC0}Eox@+Les&(uZayF_xi(L zx2FuCdL~{qYHWer=O+>`9!P3-5RQ%$g`>MWJMSD$$EHxu$HO1J1iS>6B?0Cq@!($; zHBZM&U|AB#<#KPm_11U4``vr@?o}!kya1L(`9-7S;r@#@;vd>y047f2O29lE0_i~S z;B~|Cf@2_5x4>$W)Q}{fk@Jq?Dj~;XL49+%;aV_IsU(%#6C@enZxwvcX7JM8lL=ZI zq`<|=WP+rR5ANO-Fppq+)_ti0I;hFxmpx)PzonI&IV%ET>f{6+T;UHAEgPJcT|)xO;e;ll zY@VT3yGJlLHFRx~g<(~5=entLw-LTQoQwyt_%s}^-MKfL)Ocsj8}~;q0WX22NdUNC ztMU2ro0q`Zk^sM-=g*)2;SYbv2{wKoQ2yM*VTlYpuKb{AZ`e8amzt-dm!4bgw>QoO+3c5gW^h` zWxxs^@8)Q8euv}n<{rw9jtYXi%k`^QP;M~AL-WbwCwsel&<5iYBOolS%}(cdUsyj8 zn}){4aDJY!K7MkvE~-)!5oT9CIaFD=ddoG8Ixg%WS}tx26Hi;u%ZjxcK|99M~)W@cKBy1cH+PXhr4e7-|%CqlJl{cwp6=x9Wr>!Pv$LV$xIEV>2#@ z`|Y&5IEvYO$JlaDtP;Cm#B^khFOqVyy4PTmE!21SYLE6O!v<@GIr@I@CEz8nED7Mr z<3n|qB}`9exe~zmMX2uEZ@?4Dkpaa;Db->FdZ*H9;Ia60+wqCf zn%@nMCl9WMP^)+kUf~ck2HV%R^Vuv3L!;?b^{96LFZa5gZYGn1XD~G2*cteRsHFqw zT3-3ee3}^chqa>yPjHB55i6!dAdOmL9ik@_++aw-xxZH>QO$*obJWV0OGk&bNB17# z#F#5)QM0FA%$t%~dq*e-@E?=)R+`*F9~LGN(%{oYH!OJG?NU=1UDqrIoZ zvgGOMEKvgdrZ9K?gCG2$P$;aY%W%|Kg1G$M%%uEz@i+kL!k@KIju~91PXK za9(`cfcw)4ZX^Ic!DmO06L6`)eFw<}rm_2i5Y1ggAkd1k3#z=A5y3skplq1~XgE21yu)fxGIa}BT9d+qDs3;-6H$BV45hnT;Tit8?Dl#`Rk_s?Yl}-2;SKlRy;nb~6-)V4CP~x1 z?&xr@j@g6B5HPfi>U7NX)EWsW62`a>NJdy{$ zy@I2W)zI>9+JH1oF#mKy+K_2Hz5nQOZMQ*qu{Gj%UIJbMOOrsW)q3~ccX8j>$IowG z0%uGD{B(ZnTi?RK?=$l}_sDp-|J>gVwU!8axN@$?6|~Y9|EMa&-j??aCD(4JArO}r!By!5!MWXq4xkKO0f|3G|IL!pzEHxq5_mO!fzOSl6{|rZ?Rx; zrPdu|i=Vgoi9LGX_&Sdi$1v;w_aQn9t#4ddDXkJ!3N@1JKfM3o_rLqUq^~647*jSM zFd=<`et}*geNy4z&dy{>GFDzG47$C;!wOk73Gjt6q9qU=tZIz_HGrtpcL*{j*<3oF zh@=adUbp|~&LcP|uH>hoNvGYbAGRuoGVlvgv#Bp~-={@g&t){4jtL~rW>SnJ)Zq)$ zezVb&TfGKU8zdM`Z27rt_RX(<4M%=j2kmz{Jz^i|jymsJp^An&sA#p_^nhAq6Wq5M z9xJ1F4g8=zv^&rn5Z; -uniform texture2d InputA< - bool automatic = true; ->; - -uniform int mode; - -sampler_state textureSampler { - Filter = Linear; - AddressU = Clamp; - AddressV = Clamp; -}; - -struct VertData { - float4 pos : POSITION; - float2 uv : TEXCOORD0; -}; - -VertData VSDefault(VertData vtx) -{ - vtx.pos = mul(float4(vtx.pos.xyz, 1.0), ViewProj); - return vtx; -} - -float4 PSAlphaFilter(VertData vtx) : TARGET -{ - float2 uv = vtx.uv; - float3 pixel = InputA.Sample(textureSampler, float2(vtx.uv.x, vtx.uv.y)).rgb; - float alpha = InputA.Sample(textureSampler, float2(vtx.uv.x + 0.5, vtx.uv.y)).g; - return float4(clamp(pixel.rgb / alpha, 0.0, 1.0), alpha); -} - -technique Draw -{ - pass - { - vertex_shader = VSDefault(vtx); - pixel_shader = PSAlphaFilter(vtx); - } -} \ No newline at end of file From fc082587b6e888679c4dafe06ecd1107e4386a81 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Sun, 22 May 2022 22:25:09 +0800 Subject: [PATCH 15/21] launcher --- launcher.py | 51 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/launcher.py b/launcher.py index 0320d1c..5847c22 100644 --- a/launcher.py +++ b/launcher.py @@ -6,20 +6,26 @@ import tkinter as tk from tkinter import ttk import json -try: - f = open('launcher.json') - args = json.load(f) - f.close() -except: - args = { +default_arg={ 'character': 'y', 'input': 2, 'output': 2, 'ifm': None, 'is_extend_movement': False, 'is_anime4k': False, + 'is_alpha_split': False, + 'cache_simplify': 1, + 'cache_size': 1, } +try: + f = open('launcher.json') + args = json.load(f) + default_arg.update(args) + f.close() +finally: + args = default_arg + p = None characterList = [] @@ -52,6 +58,23 @@ ttk.Label(launcher, text="iFacialMocap IP:Port").pack(fill='x', expand=True) ifm = tk.StringVar(value=args['ifm']) ttk.Entry(launcher, textvariable=ifm, state=False).pack(fill='x', expand=True) +ttk.Label(launcher, text="Facial Input Simplify").pack(fill='x', expand=True) +cache_simplify = tk.IntVar(value=args['cache_simplify']) +ttk.Radiobutton(launcher, text='Off', value=0, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='Low', value=1, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='Medium', value=2, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='High', value=3, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='Higher', value=4, variable=cache_simplify).pack(fill='x', expand=True) + +ttk.Label(launcher, text="Cache Size").pack(fill='x', expand=True) +cache_size = tk.IntVar(value=args['cache_size']) +ttk.Radiobutton(launcher, text='Off', value=0, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='256M', value=1, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='1GB', value=2, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='2GB', value=3, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='4GB', value=4, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='8GB', value=5, variable=cache_size).pack(fill='x', expand=True) + ttk.Label(launcher, text="Extra Options").pack(fill='x', expand=True) is_extend_movement = tk.BooleanVar(value=args['is_extend_movement']) ttk.Checkbutton(launcher, text='Extend Movement', variable=is_extend_movement).pack(fill='x', expand=True) @@ -59,6 +82,9 @@ ttk.Checkbutton(launcher, text='Extend Movement', variable=is_extend_movement).p is_anime4k = tk.BooleanVar(value=args['is_anime4k']) ttk.Checkbutton(launcher, text='Anime4K', variable=is_anime4k).pack(fill='x', expand=True) +is_alpha_split = tk.BooleanVar(value=args['is_alpha_split']) +ttk.Checkbutton(launcher, text='Alpha Split', variable=is_alpha_split).pack(fill='x', expand=True) + output = tk.IntVar(value=args['output']) ttk.Label(launcher, text="Output").pack(fill='x', expand=True) ttk.Radiobutton(launcher, text='Unity Capture', value=0, variable=output).pack(fill='x', expand=True) @@ -76,6 +102,9 @@ def launch(): 'ifm': ifm.get(), 'is_extend_movement': is_extend_movement.get(), 'is_anime4k': is_anime4k.get(), + 'is_alpha_split': is_alpha_split.get(), + 'cache_simplify': cache_simplify.get(), + 'cache_size': cache_size.get(), } f = open('launcher.json', mode='w') json.dump(args, f) @@ -111,12 +140,20 @@ def launch(): run_args.append('--debug') if args['is_anime4k']: run_args.append('--anime4k') + if args['is_alpha_split']: + run_args.append('--alpha_split') if args['is_extend_movement']: run_args.append('--extend_movement') run_args.append('1') + if args['cache_simplify'] is not None: + run_args.append('--simplify') + run_args.append(str(args['cache_simplify'])) + if args['cache_size'] is not None: + run_args.append('--cache') + run_args.append(['0b','256mb','1gb','2gb','4gb','8gb'][args['cache_size']]) run_args.append('--output_size') run_args.append('512x512') - + print(run_args) p = subprocess.Popen(run_args) launch_btn.config(text='Stop') From 8cb2320f3c26912ba9c81a9943ea5691ef3b6849 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Mon, 23 May 2022 23:02:54 +0800 Subject: [PATCH 16/21] f --- launcher.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launcher.py b/launcher.py index 5847c22..5ac88fe 100644 --- a/launcher.py +++ b/launcher.py @@ -133,10 +133,10 @@ def launch(): if args['output'] == 0: run_args.append('--output_webcam') run_args.append('unitycapture') - elif args['input'] == 1: + elif args['output'] == 1: run_args.append('--output_webcam') run_args.append('obs') - elif args['input'] == 2: + elif args['output'] == 2: run_args.append('--debug') if args['is_anime4k']: run_args.append('--anime4k') From cf218fc1a108f106f2176744132f3a604772f2b4 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Tue, 24 May 2022 00:25:51 +0800 Subject: [PATCH 17/21] better fps counter --- main.py | 68 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/main.py b/main.py index 1700da4..4025fb4 100644 --- a/main.py +++ b/main.py @@ -27,6 +27,21 @@ from tha2.mocap.ifacialmocap_constants import * from args import args +import collections + + +class FPS: + def __init__(self, avarageof=50): + self.frametimestamps = collections.deque(maxlen=avarageof) + + def __call__(self): + self.frametimestamps.append(time.time()) + if len(self.frametimestamps) > 1: + return len(self.frametimestamps) / (self.frametimestamps[-1] - self.frametimestamps[0]) + else: + return 0.0 + + device = torch.device('cuda') if torch.cuda.is_available() and not args.skip_model else torch.device('cpu') @@ -64,6 +79,7 @@ class IFMClientProcess(Process): self.should_terminate = Value('b', False) self.address = args.ifm.split(':')[0] self.port = int(args.ifm.split(':')[1]) + self.ifm_fps_number=Value('f',0.0) self.perf_time = 0 def run(self): @@ -80,6 +96,8 @@ class IFMClientProcess(Process): self.socket.setblocking(False) self.socket.bind(("", self.port)) self.socket.settimeout(0.1) + ifm_fps=FPS() + pre_socket_string='' while True: if self.should_terminate.value: break @@ -92,13 +110,13 @@ class IFMClientProcess(Process): else: raise e socket_string = socket_bytes.decode("utf-8") + if args.debug and pre_socket_string!=socket_string: + self.ifm_fps_number.value=ifm_fps() + pre_socket_string=socket_string # print(socket_string) # blender_data = json.loads(socket_string) data = self.convert_from_blender_data(socket_string) - # cur_time = time.perf_counter() - # fps = 1 / (cur_time - self.perf_time) - # self.perf_time = cur_time - # print(fps) + try: self.queue.put_nowait(data) except queue.Full: @@ -144,6 +162,8 @@ class ModelClientProcess(Process): self.input_image = input_image self.output_queue = Queue() self.input_queue = Queue() + self.model_fps_number=Value('f',0.0) + self.cache_hit_ratio=Value('f',0.0) def run(self): model = None @@ -163,7 +183,7 @@ class ModelClientProcess(Process): model_cache = OrderedDict() tot = 0 hit = 0 - + model_fps = FPS() while True: model_input = None try: @@ -264,16 +284,16 @@ class ModelClientProcess(Process): model_input[ifm_converter.eye_happy_wink_left_index - 12] = model_input[ ifm_converter.eye_happy_wink_left_index - 12] / 2 model_input[ifm_converter.mouth_aaa_index - 12] = min( - model_input[ifm_converter.mouth_aaa_index - 12]+ - model_input[ifm_converter.mouth_ooo_index - 12]/2+ - model_input[ifm_converter.mouth_iii_index - 12]/2+ - model_input[ifm_converter.mouth_uuu_index - 12]/2,1 + model_input[ifm_converter.mouth_aaa_index - 12] + + model_input[ifm_converter.mouth_ooo_index - 12] / 2 + + model_input[ifm_converter.mouth_iii_index - 12] / 2 + + model_input[ifm_converter.mouth_uuu_index - 12] / 2, 1 ) - model_input[ifm_converter.mouth_ooo_index - 12]=0 - model_input[ifm_converter.mouth_iii_index - 12]=0 - model_input[ifm_converter.mouth_uuu_index - 12]=0 - for i in range(4,args.simplify): - simplify_arr=[max(math.ceil(x*0.8),5)for x in simplify_arr] + model_input[ifm_converter.mouth_ooo_index - 12] = 0 + model_input[ifm_converter.mouth_iii_index - 12] = 0 + model_input[ifm_converter.mouth_uuu_index - 12] = 0 + for i in range(4, args.simplify): + simplify_arr = [max(math.ceil(x * 0.8), 5) for x in simplify_arr] for i in range(12, len(simplify_arr)): if simplify_arr[i] > 0: model_input[i - 12] = round(model_input[i - 12] * simplify_arr[i]) / simplify_arr[i] @@ -284,8 +304,7 @@ class ModelClientProcess(Process): self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit += 1 - if (args.perf) and hit % 20 == 0: - print('cached', str(hit / tot * 100) + '%') + self.cache_hit_ratio.value=hit / tot else: if args.perf: tic = time.perf_counter() @@ -315,6 +334,8 @@ class ModelClientProcess(Process): model_cache[input_hash] = postprocessed_image if len(model_cache) > args.max_cache_len: model_cache.popitem(0) + if args.debug: + self.model_fps_number.value=model_fps() @torch.no_grad() @@ -330,6 +351,8 @@ def main(): print("Character Image Loaded:", args.character) cap = None + output_fps=FPS() + if not args.debug_input: if args.ifm is not None: @@ -391,7 +414,6 @@ def main(): pose_queue = [] blender_data = create_default_blender_data() - tic1 = 0 model_output = None model_process = ModelClientProcess(input_image) @@ -569,6 +591,8 @@ def main(): print("extendmovement", (time.perf_counter() - tic) * 1000) tic = time.perf_counter() + output_fps_number=output_fps() + if args.anime4k: alpha_channel = postprocessed_image[:, :, 3] alpha_channel = cv2.resize(alpha_channel, None, fx=2, fy=2) @@ -595,11 +619,11 @@ def main(): output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) # resized_frame = cv2.resize(output_frame, (np.min(debug_image.shape[:2]), np.min(debug_image.shape[:2]))) # output_frame = np.concatenate([debug_image, resized_frame], axis=1) - toc = time.perf_counter() - fps = 1 / (toc - tic1) - tic1 = toc - cv2.putText(output_frame, str('%.1f' % fps), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) - # cv2.putText(output_frame, str('%.1f' % (missed_count/changed_count*100)), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('OUT_FPS:%.1f' % output_fps_number), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('INP_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 32), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('GPU_FPS:%.1f' % model_process.model_fps_number.value), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + if args.max_cache_len>0: + cv2.putText(output_frame, str('CACHED:%.1f%%' % (model_process.cache_hit_ratio.value*100)), (0, 64), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) # cv2.imshow("camera", debug_image) cv2.waitKey(1) From 250e71c70058d1d44c36b6d9e77bcd2ca92352d0 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Tue, 24 May 2022 00:27:39 +0800 Subject: [PATCH 18/21] better fps counter --- main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 4025fb4..441c101 100644 --- a/main.py +++ b/main.py @@ -620,8 +620,10 @@ def main(): # resized_frame = cv2.resize(output_frame, (np.min(debug_image.shape[:2]), np.min(debug_image.shape[:2]))) # output_frame = np.concatenate([debug_image, resized_frame], axis=1) cv2.putText(output_frame, str('OUT_FPS:%.1f' % output_fps_number), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) - cv2.putText(output_frame, str('INP_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 32), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) - cv2.putText(output_frame, str('GPU_FPS:%.1f' % model_process.model_fps_number.value), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('GPU_FPS:%.1f' % model_process.model_fps_number.value), (0, 32), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + if args.ifm is not None: + cv2.putText(output_frame, str('IFM_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) if args.max_cache_len>0: cv2.putText(output_frame, str('CACHED:%.1f%%' % (model_process.cache_hit_ratio.value*100)), (0, 64), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) From 3cfa72ef891634e7979cdc8da47ac478d5000c7d Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Tue, 24 May 2022 01:53:50 +0800 Subject: [PATCH 19/21] better fps counter --- main.py | 51 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/main.py b/main.py index 441c101..04bf565 100644 --- a/main.py +++ b/main.py @@ -79,7 +79,7 @@ class IFMClientProcess(Process): self.should_terminate = Value('b', False) self.address = args.ifm.split(':')[0] self.port = int(args.ifm.split(':')[1]) - self.ifm_fps_number=Value('f',0.0) + self.ifm_fps_number = Value('f', 0.0) self.perf_time = 0 def run(self): @@ -96,8 +96,8 @@ class IFMClientProcess(Process): self.socket.setblocking(False) self.socket.bind(("", self.port)) self.socket.settimeout(0.1) - ifm_fps=FPS() - pre_socket_string='' + ifm_fps = FPS() + pre_socket_string = '' while True: if self.should_terminate.value: break @@ -110,9 +110,9 @@ class IFMClientProcess(Process): else: raise e socket_string = socket_bytes.decode("utf-8") - if args.debug and pre_socket_string!=socket_string: - self.ifm_fps_number.value=ifm_fps() - pre_socket_string=socket_string + if args.debug and pre_socket_string != socket_string: + self.ifm_fps_number.value = ifm_fps() + pre_socket_string = socket_string # print(socket_string) # blender_data = json.loads(socket_string) data = self.convert_from_blender_data(socket_string) @@ -162,8 +162,9 @@ class ModelClientProcess(Process): self.input_image = input_image self.output_queue = Queue() self.input_queue = Queue() - self.model_fps_number=Value('f',0.0) - self.cache_hit_ratio=Value('f',0.0) + self.model_fps_number = Value('f', 0.0) + self.gpu_fps_number = Value('f', 0.0) + self.cache_hit_ratio = Value('f', 0.0) def run(self): model = None @@ -184,6 +185,7 @@ class ModelClientProcess(Process): tot = 0 hit = 0 model_fps = FPS() + gpu_fps = FPS() while True: model_input = None try: @@ -304,7 +306,7 @@ class ModelClientProcess(Process): self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit += 1 - self.cache_hit_ratio.value=hit / tot + self.cache_hit_ratio.value = hit / tot else: if args.perf: tic = time.perf_counter() @@ -330,12 +332,14 @@ class ModelClientProcess(Process): tic = time.perf_counter() self.output_queue.put_nowait(postprocessed_image) + if args.debug: + self.gpu_fps_number.value = gpu_fps() if args.max_cache_len > 0: model_cache[input_hash] = postprocessed_image if len(model_cache) > args.max_cache_len: model_cache.popitem(0) if args.debug: - self.model_fps_number.value=model_fps() + self.model_fps_number.value = model_fps() @torch.no_grad() @@ -351,7 +355,7 @@ def main(): print("Character Image Loaded:", args.character) cap = None - output_fps=FPS() + output_fps = FPS() if not args.debug_input: @@ -591,7 +595,7 @@ def main(): print("extendmovement", (time.perf_counter() - tic) * 1000) tic = time.perf_counter() - output_fps_number=output_fps() + output_fps_number = output_fps() if args.anime4k: alpha_channel = postprocessed_image[:, :, 3] @@ -619,13 +623,24 @@ def main(): output_frame = cv2.cvtColor(postprocessed_image, cv2.COLOR_RGBA2BGRA) # resized_frame = cv2.resize(output_frame, (np.min(debug_image.shape[:2]), np.min(debug_image.shape[:2]))) # output_frame = np.concatenate([debug_image, resized_frame], axis=1) - cv2.putText(output_frame, str('OUT_FPS:%.1f' % output_fps_number), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) - cv2.putText(output_frame, str('GPU_FPS:%.1f' % model_process.model_fps_number.value), (0, 32), - cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('OUT_FPS:%.1f' % output_fps_number), (0, 16), cv2.FONT_HERSHEY_PLAIN, 1, + (0, 255, 0), 1) + if args.max_cache_len > 0: + cv2.putText(output_frame, str( + 'GPU_FPS:%.1f / %.1f' % (model_process.model_fps_number.value, model_process.gpu_fps_number.value)), + (0, 32), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + else: + cv2.putText(output_frame, str( + 'GPU_FPS:%.1f' % (model_process.model_fps_number.value)), + (0, 32), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) if args.ifm is not None: - cv2.putText(output_frame, str('IFM_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) - if args.max_cache_len>0: - cv2.putText(output_frame, str('CACHED:%.1f%%' % (model_process.cache_hit_ratio.value*100)), (0, 64), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + cv2.putText(output_frame, str('IFM_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 48), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + if args.max_cache_len > 0: + cv2.putText(output_frame, str('CACHED:%.1f%%' % (model_process.cache_hit_ratio.value * 100)), (0, 64), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) # cv2.imshow("camera", debug_image) cv2.waitKey(1) From ca0839c0bddf45859a08a67d0cf001bf09f9dfe3 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Tue, 24 May 2022 21:40:46 +0800 Subject: [PATCH 20/21] gpu_cache --- args.py | 7 ++++++- main.py | 14 ++++++++++---- models.py | 22 ++++++++++++++++++++-- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/args.py b/args.py index ea13ae3..368d1d1 100644 --- a/args.py +++ b/args.py @@ -24,7 +24,8 @@ parser.add_argument('--skip_model', action='store_true') parser.add_argument('--ifm', type=str) parser.add_argument('--anime4k', action='store_true') parser.add_argument('--alpha_split', action='store_true') -parser.add_argument('--cache', type=str, default='100mb') +parser.add_argument('--cache', type=str, default='256mb') +parser.add_argument('--gpu_cache', type=str, default='512mb') parser.add_argument('--simplify', type=int, default=1) args = parser.parse_args() args.output_w = int(args.output_size.split('x')[0]) @@ -33,4 +34,8 @@ if args.cache is not None: args.max_cache_len=int(convert_to_byte(args.cache)/262144) else: args.max_cache_len=0 +if args.gpu_cache is not None: + args.max_gpu_cache_len=int(convert_to_byte(args.gpu_cache)/589824) +else: + args.max_gpu_cache_len=0 if args.output_webcam is None and args.output_dir is None: args.debug = True \ No newline at end of file diff --git a/main.py b/main.py index 04bf565..36d7f49 100644 --- a/main.py +++ b/main.py @@ -165,6 +165,7 @@ class ModelClientProcess(Process): self.model_fps_number = Value('f', 0.0) self.gpu_fps_number = Value('f', 0.0) self.cache_hit_ratio = Value('f', 0.0) + self.gpu_cache_hit_ratio= Value('f', 0.0) def run(self): model = None @@ -302,22 +303,23 @@ class ModelClientProcess(Process): input_hash = hash(tuple(model_input)) cached = model_cache.get(input_hash) tot += 1 + mouth_eye_vector_c=[0.0]*27 if not cached is None: self.output_queue.put_nowait(cached) model_cache.move_to_end(input_hash) hit += 1 - self.cache_hit_ratio.value = hit / tot else: if args.perf: tic = time.perf_counter() for i in range(27): mouth_eye_vector[0, i] = model_input[i] + mouth_eye_vector_c[i]=model_input[i] for i in range(3): pose_vector[0, i] = model_input[i + 27] if model is None: output_image = input_image else: - output_image = model(input_image, mouth_eye_vector, pose_vector) + output_image = model(input_image, mouth_eye_vector, pose_vector, mouth_eye_vector_c,self.gpu_cache_hit_ratio) if args.perf: torch.cuda.synchronize() print("model", (time.perf_counter() - tic) * 1000) @@ -337,9 +339,10 @@ class ModelClientProcess(Process): if args.max_cache_len > 0: model_cache[input_hash] = postprocessed_image if len(model_cache) > args.max_cache_len: - model_cache.popitem(0) + model_cache.popitem(last=False) if args.debug: self.model_fps_number.value = model_fps() + self.cache_hit_ratio.value = hit / tot @torch.no_grad() @@ -639,7 +642,10 @@ def main(): cv2.putText(output_frame, str('IFM_FPS:%.1f' % client_process.ifm_fps_number.value), (0, 48), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) if args.max_cache_len > 0: - cv2.putText(output_frame, str('CACHED:%.1f%%' % (model_process.cache_hit_ratio.value * 100)), (0, 64), + cv2.putText(output_frame, str('MEMCACHED:%.1f%%' % (model_process.cache_hit_ratio.value * 100)), (0, 64), + cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) + if args.max_gpu_cache_len > 0: + cv2.putText(output_frame, str('GPUCACHED:%.1f%%' % (model_process.gpu_cache_hit_ratio.value * 100)), (0, 80), cv2.FONT_HERSHEY_PLAIN, 1, (0, 255, 0), 1) cv2.imshow("frame", output_frame) # cv2.imshow("camera", debug_image) diff --git a/models.py b/models.py index e7bcf07..09f415b 100644 --- a/models.py +++ b/models.py @@ -6,18 +6,36 @@ from tha2.poser.modes.mode_20 import load_face_morpher, load_face_rotater, load_ from args import args +from collections import OrderedDict + class TalkingAnimeLight(nn.Module): def __init__(self): super(TalkingAnimeLight, self).__init__() self.face_morpher = load_face_morpher('pretrained/face_morpher.pt') self.two_algo_face_rotator = load_face_rotater('pretrained/two_algo_face_rotator.pt') self.combiner = load_combiner('pretrained/combiner.pt') + self.face_cache = OrderedDict() + self.tot = 0 + self.hit = 0 - def forward(self, image, mouth_eye_vector, pose_vector): + def forward(self, image, mouth_eye_vector, pose_vector, mouth_eye_vector_c, ratio=None): x = image.clone() if args.perf: tic=time.perf_counter() - mouth_eye_morp_image = self.face_morpher(image[:, :, 32:224, 32:224], mouth_eye_vector) + input_hash = hash(tuple(mouth_eye_vector_c)) + cached = self.face_cache.get(input_hash) + self.tot+=1 + if cached is None: + mouth_eye_morp_image = self.face_morpher(image[:, :, 32:224, 32:224], mouth_eye_vector) + self.face_cache[input_hash]=mouth_eye_morp_image.detach() + if len(self.face_cache) > args.max_gpu_cache_len: + self.face_cache.popitem(last=False) + else: + self.hit+=1 + mouth_eye_morp_image=cached + self.face_cache.move_to_end(input_hash) + if args.debug and ratio is not None: + ratio.value=self.hit / self.tot if args.perf: print(" - face_morpher",(time.perf_counter()-tic)*1000) tic=time.perf_counter() From b88cdcc615db923443a27b64846d5392d38b2fb6 Mon Sep 17 00:00:00 2001 From: yuyuyzl Date: Tue, 24 May 2022 22:28:19 +0800 Subject: [PATCH 21/21] gpu_cache --- launcher.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/launcher.py b/launcher.py index 5ac88fe..e94259e 100644 --- a/launcher.py +++ b/launcher.py @@ -65,15 +65,17 @@ ttk.Radiobutton(launcher, text='Low', value=1, variable=cache_simplify).pack(fil ttk.Radiobutton(launcher, text='Medium', value=2, variable=cache_simplify).pack(fill='x', expand=True) ttk.Radiobutton(launcher, text='High', value=3, variable=cache_simplify).pack(fill='x', expand=True) ttk.Radiobutton(launcher, text='Higher', value=4, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='Highest', value=6, variable=cache_simplify).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='Gaming', value=8, variable=cache_simplify).pack(fill='x', expand=True) -ttk.Label(launcher, text="Cache Size").pack(fill='x', expand=True) +ttk.Label(launcher, text="Cache Size (RAM+VRAM)").pack(fill='x', expand=True) cache_size = tk.IntVar(value=args['cache_size']) ttk.Radiobutton(launcher, text='Off', value=0, variable=cache_size).pack(fill='x', expand=True) -ttk.Radiobutton(launcher, text='256M', value=1, variable=cache_size).pack(fill='x', expand=True) -ttk.Radiobutton(launcher, text='1GB', value=2, variable=cache_size).pack(fill='x', expand=True) -ttk.Radiobutton(launcher, text='2GB', value=3, variable=cache_size).pack(fill='x', expand=True) -ttk.Radiobutton(launcher, text='4GB', value=4, variable=cache_size).pack(fill='x', expand=True) -ttk.Radiobutton(launcher, text='8GB', value=5, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='256M+128M', value=1, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='1GB+512M', value=2, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='2GB+1GB', value=3, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='4GB+2GB', value=4, variable=cache_size).pack(fill='x', expand=True) +ttk.Radiobutton(launcher, text='8GB+4GB', value=5, variable=cache_size).pack(fill='x', expand=True) ttk.Label(launcher, text="Extra Options").pack(fill='x', expand=True) is_extend_movement = tk.BooleanVar(value=args['is_extend_movement']) @@ -151,6 +153,8 @@ def launch(): if args['cache_size'] is not None: run_args.append('--cache') run_args.append(['0b','256mb','1gb','2gb','4gb','8gb'][args['cache_size']]) + run_args.append('--gpu_cache') + run_args.append(['0b','128mb','512mb','1gb','2gb','4gb'][args['cache_size']]) run_args.append('--output_size') run_args.append('512x512') print(run_args)